版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
传送门
题解:
话说 BJOI2019 Day2 稍微难点的就这一道啊,而且这道题也不算特别难的。
那BJ今年省选Day1爆炸的岂不是翻盘无望
首先考虑一个正确性显然的贪心。
我们把所有数放到数轴上,重复的叠起来,然后把 中的柱子(宽度忽略不计)向左边推倒。没有覆盖的位置总数就是答案。
于是我们维护一个全局位移标记,线段树维护每个点覆盖次数,区间 的个数。修改就很好处理了。
需要注意的是我们并不能把 之后的柱子推倒,所以在区间右端点滑动的时候需要考虑更新,左端点不用,因为左端点滑过去的时候一定是把这个柱子扔出区间外的时候,不会影响询问。所以线段树还要支持区间加,由于覆盖次数一定是非负,维护区间最小值出现次数即可维护区间 的个数。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;bool f=0;
while(!isdigit(c=gc()))f=c=='-';num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return f?-num:num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
inline int min(int a,int b){return a<b?a:b;}
cs int N=1.5e5+7,M=4e6+7;
int n,m,b,ps,nn,a[N],ct[M];
#define lc u<<1
#define rc u<<1|1
int mn[M],tim[M];
inline void pushup(int u,int tag){
mn[u]=std::min(mn[lc],mn[rc]);
tim[u]=(mn[u]==mn[lc]?tim[lc]:0)+(mn[u]==mn[rc]?tim[rc]:0);
mn[u]+=tag;
}
inline void build(int u,int l,int r){
if(l==r){mn[u]=0,tim[u]=1;return;}
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
pushup(u,0);
}
inline void update(int u,int l,int r,int p,int w){
if(l==r){mn[u]+=w;return ;}
int mid=l+r>>1,tag=mn[u]-min(mn[lc],mn[rc]);
(p<=mid)?update(lc,l,mid,p,w):update(rc,mid+1,r,p,w);
pushup(u,tag);
}
inline void modify(int u,int l,int r,int ql,int qr,int w){
if(ql<=l&&r<=qr){mn[u]+=w;return ;}
int mid=l+r>>1,tag=mn[u]-min(mn[lc],mn[rc]);
if(ql<=mid)modify(lc,l,mid,ql,qr,w);
if(mid<qr)modify(rc,mid+1,r,ql,qr,w);
pushup(u,tag);
}
inline int query(int u,int l,int r,int ql,int qr,int ad=0){
if(ql<=l&&r<=qr)return mn[u]+ad==0?tim[u]:0;
int mid=l+r>>1,tag=mn[u]-min(mn[lc],mn[rc]);
if(qr<=mid)return query(lc,l,mid,ql,qr,tag+ad);
if(mid<ql)return query(rc,mid+1,r,ql,qr,tag+ad);
return query(lc,l,mid,ql,qr,tag+ad)+query(rc,mid+1,r,ql,qr,tag+ad);
}
#undef lc
#undef rc
inline void ins(int x){
int p=x-(ct[x]++);
if(x<=ps+n)update(1,1,nn,p,1);
}
inline void del(int x){
int p=x-(--ct[x]);
if(x<=ps+n)update(1,1,nn,p,-1);
}
signed main(){
#ifdef zxyoi
freopen("number.in","r",stdin);
#endif
n=gi(),m=gi(),nn=(n+m)<<1;b=ps=n+m;build(1,1,nn);
for(int re i=1;i<=n;++i)ins(a[i]=gi()+b);
while(m--){
int p=gi(),x=gi();
if(p)del(a[p]),ins(a[p]=ps+x);
else {
if(x==-1){++ps;if(ct[ps+n])x=ps+n,modify(1,1,nn,x-ct[x]+1,x,1);}
else {if(ct[ps+n])x=ps+n,modify(1,1,nn,x-ct[x]+1,x,-1);--ps;}
}
cout<<query(1,1,nn,ps+1,ps+n)<<"\n";
}
return 0;
}