BZOJ4068 : [Ctsc2015]app
对于一个所选任务集合,如果对于任意时刻$i$,$i$前面所选任务数都不超过i的话,那么这些任务可以全选。
维护一棵线段树$T$,第$i$个位置一开始为$i$,每使用一个任务,$[t,T]$都要减$1$。
插入一个任务:
首先查询$[t,T]$的区间内第一个$0$的位置,记为$k$。
如果没有$0$,那么可以直接加入这个任务。
否则要么不用这个任务,要么拿这个任务去替换$t$在$[1,k]$里价值最小的任务。
删除一个任务:
如果没有使用,那么直接删除。
否则$[t,T]$都要加$1$,然后找到最后一个$0$的位置$k$。
那么要在备用任务集合中取出$t$在$[k+1,T]$里价值最大的任务,加入答案。
于是再按$t$用两棵线段树分别维护两个集合即可。
时间复杂度$O(Q\log T)$。
#include<cstdio> #include<set> #include<map> #include<algorithm> using namespace std; typedef pair<int,int>P; const int N=300010,M=1050000; int n,m,x,y,z,g[N],nxt[N],ed,cnt;char ch;long long ans;map<P,int>id; struct E{int t,p,u;E(){}E(int _t,int _p){t=_t,p=_p,u=0;}}e[N]; inline int getid(int x,int y){ int t=id[P(x,y)],p=g[t]; g[t]=nxt[g[t]]; return p; } inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int v[M],tag[M]; inline void add1(int x,int p){v[x]+=p,tag[x]+=p;} inline void pb(int x){if(tag[x])add1(x<<1,tag[x]),add1(x<<1|1,tag[x]),tag[x]=0;} inline void up(int x){v[x]=min(v[x<<1],v[x<<1|1]);} void build(int x,int a,int b){ v[x]=a; if(a==b)return; int mid=(a+b)>>1; build(x<<1,a,mid),build(x<<1|1,mid+1,b); } void add(int x,int a,int b,int c,int d,int p){ if(c<=a&&b<=d){add1(x,p);return;} pb(x); int mid=(a+b)>>1; if(c<=mid)add(x<<1,a,mid,c,d,p); if(d>mid)add(x<<1|1,mid+1,b,c,d,p); up(x); } int left(int x,int a,int b,int c,int d){ if(v[x])return 0; if(a==b)return a; pb(x); int mid=(a+b)>>1,t=0; if(c<=mid)t=left(x<<1,a,mid,c,d); if(!t&&d>mid)t=left(x<<1|1,mid+1,b,c,d); up(x); return t; } int right(int x,int a,int b,int c,int d){ if(v[x])return 0; if(a==b)return a; pb(x); int mid=(a+b)>>1,t=0; if(d>mid)t=right(x<<1|1,mid+1,b,c,d); if(!t&&c<=mid)t=right(x<<1,a,mid,c,d); up(x); return t; } struct SegmentTree{ set<P>A[N];int cnt[N],mi[M],ma[M]; inline int umax(int a,int b){ if(!a)return b; if(!b)return a; return e[a].p>e[b].p?a:b; } inline int umin(int a,int b){ if(!a)return b; if(!b)return a; return e[a].p<e[b].p?a:b; } void add(int x,int a,int b,int c,int p){ if(a==b){ cnt[a]++; A[a].insert(P(e[p].p,p)); mi[x]=A[a].begin()->second; ma[x]=A[a].rbegin()->second; return; } int mid=(a+b)>>1; if(c<=mid)add(x<<1,a,mid,c,p);else add(x<<1|1,mid+1,b,c,p); mi[x]=umin(mi[x<<1],mi[x<<1|1]); ma[x]=umax(ma[x<<1],ma[x<<1|1]); } void del(int x,int a,int b,int c,int p){ if(a==b){ cnt[a]--; A[a].erase(P(e[p].p,p)); if(cnt[a]){ mi[x]=A[a].begin()->second; ma[x]=A[a].rbegin()->second; }else mi[x]=ma[x]=0; return; } int mid=(a+b)>>1; if(c<=mid)del(x<<1,a,mid,c,p);else del(x<<1|1,mid+1,b,c,p); mi[x]=umin(mi[x<<1],mi[x<<1|1]); ma[x]=umax(ma[x<<1],ma[x<<1|1]); } int askmin(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return mi[x]; int mid=(a+b)>>1,t=0; if(c<=mid)t=askmin(x<<1,a,mid,c,d); if(d>mid)t=umin(t,askmin(x<<1|1,mid+1,b,c,d)); return t; } int askmax(int x,int a,int b,int c,int d){ if(c<=a&&b<=d)return ma[x]; int mid=(a+b)>>1,t=0; if(c<=mid)t=askmax(x<<1,a,mid,c,d); if(d>mid)t=umax(t,askmax(x<<1|1,mid+1,b,c,d)); return t; } }T1,T2; inline void addtask(int x){ int t=e[x].t,k=left(1,1,n,t,n); if(!k){ add(1,1,n,t,n,-1); T1.add(1,1,n,t,x); e[x].u=1; ans+=e[x].p; }else{ int y=T1.askmin(1,1,n,1,k); if(e[y].p<e[x].p){ add(1,1,n,e[y].t,n,1); T1.del(1,1,n,e[y].t,y); T2.add(1,1,n,e[y].t,y); e[y].u=0; add(1,1,n,t,n,-1); T1.add(1,1,n,t,x); e[x].u=1; ans+=e[x].p-e[y].p; }else T2.add(1,1,n,t,x); } } inline void deltask(int x){ if(!e[x].u)T2.del(1,1,n,e[x].t,x); else{ ans-=e[x].p; add(1,1,n,e[x].t,n,1); T1.del(1,1,n,e[x].t,x); int k=right(1,1,n,1,n),y=T2.askmax(1,1,n,k+1,n); if(y){ add(1,1,n,e[y].t,n,-1); T2.del(1,1,n,e[y].t,y); T1.add(1,1,n,e[y].t,y); e[y].u=1; ans+=e[y].p; } } } int main(){ read(n),read(m),build(1,1,n); while(m--){ while((ch=getchar())!='A'&&ch!='D'); read(x),read(y); if(ch=='A'){ e[++ed]=E(x,y); if(!id[P(x,y)])z=id[P(x,y)]=++cnt;else z=id[P(x,y)]; nxt[ed]=g[z],g[z]=ed; addtask(ed); }else deltask(getid(x,y)); printf("%lld\n",ans); } return 0; }