【思维】线段树维护后缀和+set——cf1373G
感觉是很不错的题
很关键的一步是题意简化:有m个操作,每次操作可以在数组某点+1或-1,问每次操作后,最大的 suf[i]-(n-i+1)是多少
显然对pos进行修改,会影响到[1,pos]整个区间的后缀和。所以线段树区间更新就可以。
ps:原题意下这题细节较多,要将数组扩充到2n,并且用一个multiset维护受影响的最右端
#include<bits/stdc++.h> using namespace std; #define N 600005 #define mk make_pair int n,k,m,nn; set<pair<int,int> >s; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 int mx[N<<2],lazy[N<<2]; void build(int l,int r,int rt){ if(l==r){ mx[rt]=l-n-1;return; } int m=l+r>>1; build(lson);build(rson); mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); } void pushdown(int rt){ if(lazy[rt]){ lazy[rt<<1]+=lazy[rt]; lazy[rt<<1|1]+=lazy[rt]; mx[rt<<1]+=lazy[rt]; mx[rt<<1|1]+=lazy[rt]; lazy[rt]=0; } } void update(int L,int R,int v,int l,int r,int rt){ if(L<=l && R>=r){ lazy[rt]+=v;mx[rt]+=v;return; } pushdown(rt); int m=l+r>>1; if(L<=m)update(L,R,v,lson); if(R>m)update(L,R,v,rson); mx[rt]=max(mx[rt<<1],mx[rt<<1|1]); } int query(int L,int R,int l,int r,int rt){ if(L<=l && R>=r)return max(mx[rt],0); pushdown(rt); int m=l+r>>1,res=0; if(L<=m)res=max(res,query(L,R,lson)); if(R>m)res=max(res,query(L,R,rson)); return res; } multiset<int>ss; int main(){ cin>>n>>k>>m;nn=n*2;build(1,nn,1); while(m--){ int x,y;scanf("%d%d",&x,&y); if(s.find(mk(x,y))!=s.end()){//移除这个点 s.erase(mk(x,y)); int pos=abs(k-x)+y; update(1,pos,-1,1,nn,1); ss.erase(ss.find(pos)); if(s.size()==0){ cout<<0<<'\n'; continue; } auto p=ss.end();p--; cout<<query(1,*p,1,nn,1)<<'\n'; }else {//增加这个点 s.insert(mk(x,y)); int pos=abs(k-x)+y; update(1,pos,1,1,nn,1); ss.insert(pos); auto p=ss.end();p--; cout<<query(1,*p,1,nn,1)<<'\n'; } } }