CF2049(分割区间转合并区间)

https://codeforces.com/contest/2049/problem/F
本题的第一个点在于只有mex为2k的区间才能有贡献,并且不能存在>=2k的数,所以枚举k然后计算贡献即可
然后对于单个的k,相当于每个>=2^k的数分割了一段一段的区间,再考虑到每次加的值都大于1,然后就是一直分割区间,
然而分割区间的做法明显很麻烦,所以我们可以改分割区间为合并区间,我们把查询从后往前推,先全部加上去,然后再从后往前一个一个减,
这样的话,就是一直合并区间了,做法就显而易见,并查集维护信息,然后暴力合并即可

#include<bits/stdc++.h>

#define int long long
#define endl '\n' 
 
using namespace std;

const int N=1e6+10,INF=1e15; 

int a[N],b[N];
vector<int> vec[N];//一个桶,存储一个集合的大小 
int cnt[N],sz[N],p[N];//siz是保证合并复杂度尽可能的低,p就是普通并查集,cnt就是存储这个集合内存在多少个不同的数 
int le[N],ri[N];//一个集合的左边界和右边界 
int m;//表示当前的枚举的mex
multiset<int> se;

void de(int x){
	cout<<"nima"<<x<<endl;
}

int find(int x){
	if(p[x]!=x) return p[x]=find(p[x]);
	return p[x];
}

void add(int x,int y,int c){
	if(!vec[x].size()) return ;
	if(vec[x][y]==0) cnt[x]++;
	vec[x][y]+=c;
	if(vec[x][y]==0) cnt[x]--;
}

void er(int no){//删除操作 
	if(!se.size()) return ;
	int x=find(no);
	int len=ri[x]-le[x]+1;
//	if(se.count(len)){
		auto it=se.find(len);	
		se.erase(it);
//	} 
}

void upd(int x,int y){//更新 
	if(cnt[x]==m){
		if(y==1) {
			se.insert(ri[x]-le[x]+1);
		}
		else er(x);
	}
}

void merge(int x,int y){
	if(b[x]>=m||b[y]>=m) return ;
	int px=find(x),py=find(y);
	if(px==py) return ;
	if(sz[px]<sz[py]) swap(px,py);
	upd(px,-1),upd(py,-1);//先给他们全都删了,然后再重新插入 
	if(!vec[px].size()&&!vec[py].size()){
		int l=min(le[px],le[py]),r=max(ri[px],ri[py]);
		if(r-l+1>=m){
			vec[px].resize(m,0);//只有长度大于等于m才会给你开户 
			for(int i=l;i<=r;i++) add(px,b[i],1);	
		}
	}
	else if(!vec[py].size()){
		for(int i=le[py];i<=ri[py];i++) add(px,b[i],1);
	}else{
		for(int i=0;i<m;i++) add(px,i,vec[py][i]);
	}
	le[px]=min(le[px],le[py]);
	ri[px]=max(ri[px],ri[py]); 
	sz[px]+=sz[py];
	p[py]=px;
	upd(px,1);
}

int op[N],v[N],ans[N]; 

/*
2 2
0 0
2 1
2 1
*/

void slove(){
	int n,q;cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=q;i++){ 
		cin>>op[i]>>v[i];
		a[op[i]]+=v[i]; 
		ans[i]=0;
	}
//	cout<<"nima"<<endl;
	for(int ni=0;ni<=20;ni++){//1的p次方 
		if((1<<ni)>n) break;
		se.clear();
//		cout<<ni<<endl;
		m=1<<ni;
		for(int i=1;i<=n;i++){
			b[i]=a[i],p[i]=le[i]=ri[i]=i,cnt[i]=0,sz[i]=1,vec[i].clear();
			if(!ni&&!b[i]){
				vec[i].push_back(1);
				cnt[i]=1;
				se.insert(1);
			}
		}
		for(int i=2;i<=n;i++){
			merge(i,i-1);
		}
		for(int i=q;i>=1;i--){
			if(se.size())ans[i]=max(ans[i],*(--se.end()));
			int no=find(op[i]);
			upd(no,-1);
			add(no,b[op[i]],-1);
			b[op[i]]-=v[i];
			add(no,b[op[i]],1);
			upd(find(op[i]),1);
			if(!ni&&!b[op[i]]){
				se.insert(1);
				cnt[op[i]]=1;
				vec[op[i]].push_back(1);
			}
			if(op[i]-1!=0) merge(op[i]-1,op[i]);
			if(op[i]+1!=n+1) merge(op[i],op[i]+1);
		}
	}
	
	for(int i=1;i<=q;i++) cout<<ans[i]<<endl;
}

signed main(){
	ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
	int T=1;
	cin>>T;
	while(T--) slove();
}
posted @ 2024-12-23 18:04  MENDAXZ  阅读(1)  评论(0编辑  收藏  举报