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();
}