Luogu P5324 [BJOI2019]删数
Link
我们统计原序列的桶数组\(cnt\),对\(cnt-x\)建立平面直角坐标系。
\(\forall (x,cnt_x)\),我们覆盖数轴上\([x-cnt_x,x]\)这一段区间。
最后数轴上\([0,n]\)之间未被覆盖的长度就是答案。
单点修改就是修改两个\(cnt\),全局修改就是整体平移。
那么用线段树随便搞搞就行了。
#include<cctype>
#include<cstdio>
#include<algorithm>
const int N=500007;
int n,m,len,add,cnt[N],a[N],tag[4*N],t[4*N];
int read(){int x=0,c=getchar(),f=1;while(isspace(c))c=getchar();if(c=='-')f=-1,c=getchar();while(isdigit(c))(x*=10)+=c&15,c=getchar();return f*x;}
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)/2)
void pushup(int p,int l,int r){t[p]=tag[p]? r-l+1:t[ls]+t[rs];}
void modify(int p,int l,int r,int x){tag[p]+=x,pushup(p,l,r);}
void update(int p,int l,int r,int L,int R,int x)
{
if(R<l||r<L||R<L) return ;
if(L<=l&&r<=R) return modify(p,l,r,x);
update(ls,l,mid,L,R,x),update(rs,mid+1,r,L,R,x),pushup(p,l,r);
}
int query(int p,int l,int r,int L,int R)
{
if(R<l||r<L||R<L) return 0;
if(tag[p]) return std::min(r,R)-std::max(l,L)+1;
if(L<=l&&r<=R) return t[p];
return query(ls,l,mid,L,R)+query(rs,mid+1,r,L,R);
}
void insert(int x,int f)
{
if(add<x&&x<=add+n) update(1,1,len,x-cnt[x]+1,x,-1);
cnt[x]+=f;
if(add<x&&x<=add+n) update(1,1,len,x-cnt[x]+1,x,1);
}
#undef ls
#undef rs
#undef mid
void change(int p,int x){insert(a[p],-1),insert(a[p]=x+add,1);}
void increase(){update(1,1,len,add+n-cnt[add+n]+1,add+n,-1),update(1,1,len,add-cnt[add]+1,add,1),--add;}
void decrease(){++add,update(1,1,len,add-cnt[add]+1,add,-1),update(1,1,len,add+n-cnt[add+n]+1,add+n,1);}
void query(){printf("%d\n",n-query(1,1,len,add+1,add+n));}
int main()
{
n=read(),m=read(),len=n+m+m,add=m;
for(int i=1;i<=n;++i) insert(a[i]=read()+m,1);
for(int p,x;m;--m) p=read(),x=read(),(p? change(p,x):~x? increase():decrease()),query();
}