CF 878E Numbers on the blackboard 并查集 离线 贪心

LINK:Numbers on the blackboard

看完题觉得很难。

想了一会发现有点水 又想了一下发现有点困难。

最终想到了 但是实现的时候 也很难.

先观察题目中的这个形式 使得前后两个数字变成x+2y.

那么一个数字的变成两倍的次数固定 除了左端点至少可以变化一次.

有些数字 可以变换多次 这取决于什么 容易考虑到右端点 先变化一次 如果>0显然 可以和其左边进行合并一下.

然后 可以变换更多次 然后从右到左考虑这个过程就发现是正确的了.

这样 我们得到了一个nm的做法.

容易发现这个东西不具有区间可加性 所以不能采用线段树来维护这个东西.

不过这个过程是从左到右做的 考虑离线处理这个问题.

对于每个右端点处理左端点 显然中间的合并过程可以单调栈做一下.

考虑计算答案 单调栈存一个前缀和 然后在左端点所在区间内 再求一下值即可.

这个值可以利用线段树来做 当然也可以不需要 倒着预处理的后缀和就可以了.

一个难点是 比大小的时候可能会爆long long 这里可以预估一个INF 来防止爆掉.

也算是常见套路吧. 代码写的比较丑 因为 状态相当的不好.

const ll MAXN=100010;
ll n,m,cnt,top;
ll a[MAXN],ans[MAXN],f[MAXN],l[MAXN],r[MAXN],s[MAXN],id[MAXN];
ll qz[MAXN],hz[MAXN],mi[MAXN],INV[MAXN],w[MAXN],fac[MAXN],c[MAXN];
struct wy
{
	ll id;
	ll l,r;
}t[MAXN];
inline ll inv(ll x)
{
	return x==1?x:inv(mod%x)*(mod-mod/x)%mod;
}
inline ll cmp(wy a,wy b){return a.r<b.r;}
inline int getfather(int x){return x==f[x]?x:f[x]=getfather(f[x]);}
inline ll ksm(ll b,ll p)
{
	ll cnt=1;
	while(p)
	{
		if(p&1)cnt=cnt*b%mod;
		b=b*b%mod;p=p>>1;
	}
	return cnt;
}
int main()
{
	//freopen("1.in","r",stdin);
	get(n);get(m);mi[0]=1;fac[0]=1;
	rep(1,n,i)get(a[i]),l[i]=r[i]=f[i]=i,fac[i]=fac[i-1]*2%mod,mi[i]=min(mi[i-1]*2,INF);
	INV[n]=inv(fac[n]);hz[n]=a[n]*2%mod;
	fep(n-1,0,i)INV[i]=INV[i+1]*2%mod,hz[i]=(hz[i+1]+a[i])*2%mod;
	rep(1,m,i)
	{
		ll l,r;
		get(l);get(r);
		ans[i]=a[l];
		if(l==r)continue;
		t[++cnt]=(wy){i,l+1,r};
	}
	sort(t+1,t+1+cnt,cmp);
	ll flag=1;s[++top]=1;qz[top]=w[top]=a[1];id[1]=1;
	rep(2,n,i)
	{
		//当前端点向右移动.
		ll fa=i;ll ww=a[i]*2,ss=a[i]*2;
		while(top!=1&&ww>0)
		{
			if(ww!=INF)//更新当前块的比较值.
			{
				if(mi[(r[s[top]]-l[s[top]]+1)]==INF)ww=INF;
				else
				{
					if(ww>=(INF-1)/mi[(r[s[top]]-l[s[top]]+1)]+1)ww=INF;
					else ww=ww*mi[(r[s[top]]-l[s[top]]+1)];
				}
			}
			ss=ss*fac[(r[s[top]]-l[s[top]]+1)]%mod;
			if(ww!=INF)ww=min(INF,ww+w[top]);
			f[fa]=s[top];ss=(ss+qz[top]-qz[top-1]+mod)%mod;
			r[s[top]]=r[fa];fa=s[top];--top;
		}
		s[++top]=fa;qz[top]=(qz[top-1]+ss)%mod;w[top]=ww;id[fa]=top;
		while(flag<=cnt&&t[flag].r==i)
		{
			ll xx=getfather(t[flag].l);
			ans[t[flag].id]=(ans[t[flag].id]+qz[top]-qz[id[xx]]+mod)%mod;
			ww=hz[t[flag].l]-hz[r[xx]+1]*fac[r[xx]+1-t[flag].l];
			ans[t[flag].id]=(ans[t[flag].id]+ww)%mod;
			++flag;
		}
	}
	rep(1,m,i)putl((ans[i]+mod)%mod);
	return 0;
}
posted @ 2020-05-14 18:56  chdy  阅读(145)  评论(0编辑  收藏  举报