nm150000
发现答案相当于是值为i的数放在i号柱子上,然后将柱子向左推倒,未覆盖的位数为答案
线段树下标表示位置i被覆盖了几次,维护lazy标记,最小值及其个数
整体+1,-1操作最巧妙
我们不移动值,直接移动值域,例-1向右移,于是要在线段树前面和后面都空出max(n,m)的位置(注,当前值域的左端点代表1,右端点代表n,其余的叶子节点相应加减)
思考:若是区间修改怎么办?
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=5e5+4;
int n,m,nm,nl,nr;
int a[N],c[N],co[N<<2],lz[N<<2],mn[N<<2];
#define lc (p<<1)
#define rc (p<<1|1)
void build(int p,int l,int r){
co[p]=r-l+1;
if(l==r)return;
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
}
inline void pushup(int p){
mn[p]=min(mn[lc],mn[rc]);
if(mn[lc]==mn[rc])co[p]=co[lc]+co[rc];
else co[p]=(mn[lc]<mn[rc])?co[lc]:co[rc];
}
inline void pushdown(int p){
if(!lz[p])return;
mn[lc]+=lz[p];lz[lc]+=lz[p];
mn[rc]+=lz[p];lz[rc]+=lz[p];
lz[p]=0;
}
void modify(int p,int l,int r,int ql,int qr,int v){
if(ql<=l&&r<=qr){
mn[p]+=v;lz[p]+=v;
return;
}
int mid=l+r>>1;
pushdown(p);
if(ql<=mid)modify(lc,l,mid,ql,qr,v);
if(mid<qr)modify(rc,mid+1,r,ql,qr,v);
pushup(p);
}
int query(int p,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return mn[p]?0:co[p];
int mid=l+r>>1;
pushdown(p);
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(mid<ql)return query(rc,mid+1,r,ql,qr);
return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
}
int main(){
n=read();m=read();nm=n+max(n,m)*2;
nl=max(n,m)+1;nr=nl+n-1;
for(int i=1;i<=n;i++){
a[i]=read()+nl-1;
c[a[i]]++;
}
build(1,1,nm);
for(int i=nl;i<=nr;i++)
if(c[i])modify(1,1,nm,i-c[i]+1,i,1);
for(int i=1,op,x;i<=m;++i){
op=read();x=read();
if(op){
if(a[op]<=nr)modify(1,1,nm,a[op]-c[a[op]]+1,a[op]-c[a[op]]+1,-1);
--c[a[op]];
a[op]=x+nl-1;
++c[a[op]];
modify(1,1,nm,a[op]-c[a[op]]+1,a[op]-c[a[op]]+1,1);
}
else{
if(x==1){
if(c[nr])modify(1,1,nm,nr-c[nr]+1,nr,-1);
--nl;--nr;
}
else{
++nl;++nr;
if(c[nr])modify(1,1,nm,nr-c[nr]+1,nr,1);
}
}
cout<<query(1,1,nm,nl,nr)<<"
";
}
return (0-0);
}