CF1172F Nauuo and Bug 题解

Codeforces
Luogu

Description.

定义函数 \(f(x)\)return x<p?x:x-p
给定长度为 \(n(n\le 10^6)\) 的数列 \(a_i(a_i\in[-10^9,10^9])\),有 \(m(m\le 2\times 10^5)\) 次询问。
每次询问给定一个区间,初始 \(ans=0\),每次 \(ans\leftarrow f(ans+a_i)\),问从左到右遍历后 \(ans\) 的答案。

Solution.

相当于你有一个前缀和序列,有一条线,初始在 \(p\),每次撞到这条线线就增高 \(p\)
问最后线的位置。
然额还是很难做。

相当于每个位置是一个机器,吞进去一个数,吐出来一个数。
其实是一个分段函数,如果吞进去的数 \(\in[-\infty,p-a_i]\) 就不会 \(-p\) 否则就会。
可以考虑用线段树维护。

一个区间的分段函数段数是区间长度的,同时线段树区间总长度是 \(O(n\log n)\) 的。
然后每次 \(O(len)\) 双指针合并就行了。

Coding.

点击查看代码
//Coded by Kamiyama_Shiki on 2021.11.09 {{{
//是啊……你就是那只鬼了……所以被你碰到以后,就轮到我变成鬼了
#include<bits/stdc++.h>
using namespace std;typedef long long ll;
template<typename T>inline void read(T &x)
{
	x=0;char c=getchar(),f=0;
	for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
	for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
	f?x=-x:x;
}
template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}}
const int N=1000005;int n,q;ll p,a[N];
struct segm{vector<ll>v;ll sm;int ln;}T[N<<2];
inline void pushup(int x)
{
	int ls=x<<1,rs=x<<1|1;T[x].sm=T[ls].sm+T[rs].sm;
	T[x].v.resize(T[x].ln+2),T[x].v[0]=-1e18;
	for(int i=1;i<=T[x].ln+1;i++) T[x].v[i]=1e18;
	for(int il=0,ir=0;il<=T[ls].ln;il++)
	{
		if(ir>T[rs].ln) ir--;
		for(;ir<=T[rs].ln;ir++)
		{
			ll nw=T[rs].v[ir]+il*p-T[ls].sm;
			if(T[ls].v[il+1]-1-il*p+T[ls].sm<T[rs].v[ir]) {ir?ir--:0;break;}
			T[x].v[il+ir]=min(T[x].v[il+ir],max(T[ls].v[il],nw));
		}
	}
}
inline void build(int x,int l,int r)
{
	T[x].ln=r-l+1;if(l^r) build(x<<1,l,(l+r)>>1),build(x<<1|1,((l+r)>>1)+1,r),pushup(x);
	else T[x].sm=a[l],T[x].v.resize(3),T[x].v[0]=-1e18,T[x].v[1]=p-a[l],T[x].v[2]=1e18;
}
inline int fndps(vector<ll>&v,ll w) {return upper_bound(v.begin(),v.end(),w)-v.begin()-1;}
inline ll query(int x,int l,int r,int dl,int dr,ll dc)
{
	int md=(l+r)>>1;if(dl<=l&&r<=dr) return dc+T[x].sm-p*fndps(T[x].v,dc);
	if(dr<=md) return query(x<<1,l,md,dl,dr,dc);
	else if(dl>md) return query(x<<1|1,md+1,r,dl,dr,dc);
	else return query(x<<1|1,md+1,r,dl,dr,query(x<<1,l,md,dl,dr,dc));
}
int main()
{
	read(n,q,p);for(int i=1;i<=n;i++) read(a[i]);
	build(1,1,n);for(int l,r;q--;) read(l,r),printf("%lld\n",query(1,1,n,l,r,0));
	return 0;
}
posted @ 2021-11-09 21:35  Peal_Frog  阅读(59)  评论(0编辑  收藏  举报