csp模擬 生與死的境界【貪心】【帶權並查集】

傳送門

合併使得x,y變成一個x+2y的數,求最後剩一個數的最大值。

每次詢問針對一個區間。

首先發現,這個數列每合併一次,都會對從第二個數開始的所有數,依次多產生2^k係數的貢獻,k依次增加。

也就是說,合併兩個快,對左邊的塊沒有影響。

那麼我們從最後開始考慮,如果當前塊是正數,則和前面塊合併,會增大貢獻。反之不會。

按照這個方式進行到最後得到的塊序列除了第一塊可能爲正,其它塊和都是負數,否則可以繼續合併。

然後我們發現可以在末端添加一個數字,只要變成正的就往前合併即可。

將查詢按照r排序,如果對應r,則將l及之前所在的塊踢掉,然後強行加上l到所在快右端點的貢獻以及這一段的貢獻。帶權並查集。

這個l到右端點的後綴不會影響合併,否則後面的塊早就合併上來了。

那麼維護哈希值,直接計算即可。注意帶權並查集維護權值的時候,超過1e9就可以直接取min,因爲負數塊顯然不會有貢獻小於-1e9的。因爲我不會合並兩個負數塊到一起。

維護每一塊的左端點,右端點。

然後查詢。

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define int long long
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();
	}return cnt*f;
}
struct node{
	int l,r,id;
}que[500003];
int fa[500003],sum[500003];
int n,q,a[500003];
bool cm(node a,node b){
	return a.r<b.r;
}int ans[500003];
int jz[500003];
int pre[500003];
int S[500003];
int suf[500003];
const int mod=1e9+7;
void merge(int x,int y){
	fa[x]=y;pre[y]=pre[x];
	int len=x-pre[x];
	if(len>30&&sum[y]>0||sum[x]+(sum[y]<<len)>mod)sum[y]=mod;
	else sum[y]=sum[x]+(sum[y]<<len);
}
int query(int x,int y){
	return (suf[x]-suf[y+1]*jz[y-x+1]%mod+mod)%mod;
}
int get(int x){
	if(fa[x])return fa[x]=get(fa[x]);return x;
}
signed main(){
	n=in;q=in;
	for(int i=1;i<=n;i++)a[i]=in;
	for(int i=1;i<=q;i++){
		que[i].l=in;que[i].r=in;que[i].id=i;
	}
	sort(que+1,que+q+1,cm);jz[0]=1;
	for(int i=1;i<=n;i++){fa[i]=0;pre[i]=i-1;sum[i]=a[i];jz[i]=(jz[i-1]<<1)%mod;}
	for(int i=n;i>=1;i--)suf[i]=((suf[i+1]<<1)%mod+a[i]+mod)%mod;
//	for(int i=1;i<=q;i++)cout<<que[i].r<<" ";cout<<endl;
//	for(int i=1;i<=n;i++)cout<<pre[i]<<" ";cout<<endl;
//	for(int i=1;i<=n;i++)cout<<sum[i]<<" ";cout<<endl;
//	for(int i=1;i<=n;i++)cout<<suf[i]<<" ";cout<<endl;
//	for(int i=1;i<=n;i++)cout<<jz[i]<<" ";cout<<endl;
	int pos=0;
	for(int i=1;i<=n;i++){
		while(pre[i]&&sum[i]>=0)merge(pre[i],i);
		S[i]=(S[pre[i]]+(query(pre[i]+1,i)<<1)%mod)%mod;
//		cout<<query(pre[i]+1,i)<<endl;
		while(que[pos+1].r==i){
			int x=get(que[pos+1].l);++pos;
			ans[que[pos].id]=(S[i]-S[x]+query(que[pos].l,x)+mod)%mod;
		}
	}
	for(int i=1;i<=q;i++)cout<<ans[i]<<'\n';
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章