[BJOI2019]删数

Posted by Dispwnl on April 23, 2019

题目

题解

首先对于一个数列它的答案为

数轴上$1\sim n$中每个数能往左覆盖它的个数个点,答案就是$1\sim n$中没有被覆盖的点

因为最后满足条件的情况肯定是$1\sim n$上有且只有一层覆盖(想象一个接力的过程),修改一个数可以看成把某个重叠的部分挪到空白处

这样可以用线段树维护区间$0$的个数,需要支持区间修改和区间查询

写的有点自闭……借鉴了题解的代码

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
# define tl (k<<1)
# define tr (k<<1|1)
# define mid (l+r>>1)
using namespace std;
const int MAX=4.5e5+5;
struct p{
	int x,cnt,val,tags;
}s[MAX<<2];
int n,m,N,L,R,sL,P;
int a[MAX],cnt[MAX];
int read()
{
	int x=0,fl=1;
	char ch=getchar();
	for(;!isdigit(ch);fl=(ch=='-')?-1:1,ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x*fl;
}
void pus(int k)
{
	if(s[tl].x==s[tr].x) s[k].x=s[tl].x,s[k].cnt=s[tl].cnt+s[tr].cnt;
	else if(s[tl].x>s[tr].x) s[k].x=s[tr].x,s[k].cnt=s[tr].cnt;
	else if(s[tr].x>s[tl].x) s[k].x=s[tl].x,s[k].cnt=s[tl].cnt;
	s[k].val=s[tl].val+s[tr].val;
}
void Add(int k,int d) {s[k].x+=d,s[k].val=(!s[k].x?s[k].cnt:0),s[k].tags+=d;}
void down(int k) {if(s[k].tags) Add(tl,s[k].tags),Add(tr,s[k].tags),s[k].tags=0;}
void build(int l=0,int r=N,int k=1)
{
	s[k].val=s[k].cnt=r-l+1;
	if(l==r) return;
	build(l,mid,tl),build(mid+1,r,tr);
}
void change(int l,int r,int k,int L,int R,int d=1)
{
	if(r<L||R<l) return;
	if(l>=L&&r<=R) return void(Add(k,d));
	down(k),change(l,mid,tl,L,R,d),change(mid+1,r,tr,L,R,d),pus(k);
}
int ask(int l,int r,int k,int L,int R)
{
	if(r<L||R<l) return 0;
	if(l>=L&&r<=R) return s[k].val;
	return down(k),ask(l,mid,tl,L,R)+ask(mid+1,r,tr,L,R);
}
int main()
{
	n=read(),m=read(),N=2*m+n,L=m,R=m+n,build();
	for(int i=1;i<=n;++i)
	  ++cnt[a[i]=read()+L];
	for(int i=1+L;i<=n+L;++i)
	  if(cnt[i]) change(0,N,1,i-cnt[i]+1,i);
	for(int i=1,p,x;i<=m;++i)
	  {
	  	p=read(),x=read();
	  	if(!p)
	  	{
	  		if(x>0) change(0,N,1,R-cnt[R]+1,R,-1),change(0,N,1,L-cnt[L]+1,L),--L,--R;
	  		else ++L,++R,change(0,N,1,R-cnt[R]+1,R),change(0,N,1,L-cnt[L]+1,L,-1);
		}
		else
		{
			if(a[p]>L&&a[p]<=R) change(0,N,1,a[p]-cnt[a[p]]+1,a[p]-cnt[a[p]]+1,-1);
			--cnt[a[p]],a[p]=L+x;
			if(a[p]>L&&a[p]<=R) change(0,N,1,a[p]-cnt[a[p]],a[p]-cnt[a[p]]);
			++cnt[a[p]];
		}
		printf("%d\n",ask(0,N,1,L+1,R));
	  }
	return 0;
}