[Luogu5324][BJOI2019]删数(线段树)

时间:2023-03-10 02:49:34
[Luogu5324][BJOI2019]删数(线段树)

CF风格题,先猜结论,记数列中i这个数共出现了cnt[i]次,那么所有区间[i-cnt[i]+1,i]的并集的补集大小就是答案。

于是我们只需要线段树维护每个位置是否被某个区间覆盖到即可,对于整体加减操作,设一个偏移量即可。

 #include<cstdio>
#include<algorithm>
#define ls (x<<1)
#define rs (ls|1)
#define lson ls,L,mid
#define rson rs,mid+1,R
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
using namespace std; const int N=;
int n,m,mx,py,L,p,x,a[N],num[N],v[N<<],c[N<<],mn[N<<],tag[N<<]; void upd(int x){
if (mn[ls]<mn[rs]) mn[x]=mn[ls],c[x]=c[ls];
else if (mn[ls]>mn[rs]) mn[x]=mn[rs],c[x]=c[rs];
else mn[x]=mn[ls],c[x]=c[ls]+c[rs];
if (!mn[x]) v[x]=c[x]; else v[x]=;
} void put(int x,int k){
mn[x]+=k; tag[x]+=k;
if (!mn[x]) v[x]=c[x]; else v[x]=;
} void push(int x){
if (!tag[x]) return;
put(ls,tag[x]); put(rs,tag[x]); tag[x]=;
} void build(int x,int L,int R){
if (L==R){ c[x]=v[x]=; return; }
int mid=(L+R)>>;
build(lson); build(rson); upd(x);
} void mdf(int x,int L,int R,int l,int r,int k){
if (L==l && r==R){ put(x,k); return; }
int mid=(L+R)>>; push(x);
if (r<=mid) mdf(lson,l,r,k);
else if (l>mid) mdf(rson,l,r,k);
else mdf(lson,l,mid,k),mdf(rson,mid+,r,k);
upd(x);
} int que(int x,int L,int R,int l,int r){
if (L==l && r==R) return v[x];
int mid=(L+R)>>; push(x);
if (r<=mid) return que(lson,l,r);
else if (l>mid) return que(rson,l,r);
else return que(lson,l,mid)+que(rson,mid+,r);
} void Mdf(int x,int w){
int k=num[py+x]+(w>); num[py+x]+=w;
if (x<=n) mdf(,,mx,py+x-k+,py+x-k+,w);
} int main(){
freopen("number.in","r",stdin);
freopen("number.out","w",stdout);
scanf("%d%d",&n,&m); mx=(n+m)*+; py=n+m; build(,,mx);
rep(i,,n) scanf("%d",&a[i]),Mdf(a[i],);
while (m--){
scanf("%d%d",&p,&x);
if (p>) Mdf(a[p]+L,-),a[p]=x-L,Mdf(a[p]+L,);
else if (x>){
py--; L++; int pos=py+n+;
if (num[pos]>) mdf(,,mx,pos-num[pos]+,pos,-);
}else{
int pos=py+n+; py++; L--;
if (num[pos]>) mdf(,,mx,pos-num[pos]+,pos,);
}
printf("%d\n",que(,,mx,py+,py+n));
}
return ;
}