Description
幽香是幻想乡中一个非常有地位的人。她日理万机,事务繁多,反倒自己已经快管理不过来了。于是他决定开发一个日程管理软件来帮助自己管理任务。
对于每个任务i有一个对应的截止日期ti以及收益pi,表示若幽香能在不晚于第ti天完成这个任务,便可以得到pi的收益。幽香办事的能力非常强,任何任务都可以用恰好一天的时间做完。但由于任务实在太多了,有时候并不能完成所有任务,于是幽香会想知道这个情况下,完成任务可以给她带来的最大的累积收益是多少。
由于幻想乡的人们十分善变,任务总是不断发生着变化。幽香希望这个管理软件还能够支持插入一个任务,和删除一个任务的操作。
具体的说,幽香希望支持以下2个操作:
1.ADD t p:表示新添一个截止日期为t,收益为p的任务。
2.DEL t p:表示删除一个截止日期为t,收益为p的任务。如果有多个这样的任务,只删除一个。数据保证这样的任务一定存在。
在每次操作执行完毕后,你都需要输出能够完成的任务的最大收益和。
幽香一共有T天需要安排,从第1天到第T天。你能帮助他写出这个高效率的软件吗?
Input
第一行有两个证书T和Q,表示天数和操作的个数。
接下来Q行,其中第i行表示第i个操作,形式为ADD t p或DEL t p,其具体意义如题面所述。
Output
对每一次操作,输出一个整数在执行完该操作后幽香能够获得的最大收益和。
考虑用最大费用流表示这个贪心(每一天拆一个点x,x到x-1连费用0流量无限的边,x到T连费用0流量1的边,任务表示为S到x的流量1费用为收益的边),对于每次ADD,相当于加入一条边,这时如果有到T的增广路就直接增广(可以做这个任务而不影响其余任务),否则若可以找到正费用的增广环(用这个任务换掉一个收益更小的任务)也可以增广,否则不操作;
对于每次DEL,如果这条边没增广,就直接删边,否则需要退掉经过这条边的流量,优先考虑找一个增广环(相当于用另一个任务换掉当前任务),找不到再考虑增广路(直接删去当前任务)。
由于图的特殊性,可以用线段树和平衡树等维护增广过程。
#include<bits/stdc++.h> const int M=1e5,N=300007,inf=INT_MAX; char ib[M+7],*ip=ib+M; int G(){ if(ip==ib+M)fread(ip=ib,1,M,stdin)[ib]=0; return *ip++; } int _(){ int x=0,f=1; if(ip<ib+M-100){ while(*ip<48)*ip++=='-'?f=-1:0; while(*ip>47)x=x*10+*ip++-48; }else{ int c=G(); while(c<48)c=G(); while(c>47)x=x*10+c-48,c=G(); } return x*f; } int min(int a,int b){return a<b?a:b;} int max(int a,int b){return a>b?a:b;} int _l,_r,_a; struct node{ node*lc,*rc; int L,R,M; int mn,a; void add(int x){mn+=x,a+=x;} void dn(){if(a)lc->add(a),rc->add(a),a=0;} void up(){mn=min(lc->mn,rc->mn);} void add(){ if(_l<=L&&R<=_r)return add(_a); dn(); if(_l<=M)lc->add(); if(_r>M)rc->add(); up(); } bool ql(){ if(mn)return 0; if(L==R)return _l=L,1; return dn(),_r>M&&rc->ql()||lc->ql(); } bool qr(){ if(mn)return 0; if(L==R)return _r=R,1; return dn(),_l<=M&&lc->qr()||rc->qr(); } }ns[N*2],*np=ns,*rt; node*build(int L,int R){ node*w=np++; w->L=L,w->R=R; if(L<R){ int M=w->M=L+R>>1; w->lc=build(L,M); w->rc=build(M+1,R); } return w; } int gr(int x){return _l=x,rt->qr(),_r;} int gl(int x){return _r=x-1,rt->ql(),_l+1;} void flow(int x,int y){ if(x<y)_l=x,_r=y-1,_a=-1,rt->add(); if(x>y)_l=y,_r=x-1,_a=1,rt->add(); } std::multiset<int>e0[N],e1[N]; std::multiset<int>::iterator it; long long ans=0; int n,qp,t1[1055555],t0[1055555],mx; int em[1055555]; int pv_empty(int w){ for(w+=mx+1;;w>>=1)if(w&1&&em[w-1]&1){ for(--w;w<mx;w<<=1,w+=em[w+1]&1); return w-mx; } } int nx_full(int w){ for(w+=mx-1;w;w>>=1)if(~w&1&&em[w+1]&2){ for(++w;w<mx;w=w<<1^1,w-=em[w-1]>>1&1); return w-mx; } return 0; } void set_(int w,int v){ for(w+=mx,em[w]=v,w>>=1;w;w>>=1)em[w]=em[w<<1]|em[w<<1^1]; } void upd1(int w){ t1[w+mx]=e1[w].size()?*e1[w].begin():inf; for(w=w+mx>>1;w;w>>=1)t1[w]=min(t1[w<<1],t1[w<<1^1]); } void upd0(int w){ t0[w+mx]=e0[w].size()?*--e0[w].end():-inf; for(w=w+mx>>1;w;w>>=1)t0[w]=max(t0[w<<1],t0[w<<1^1]); } int gmn(int l,int r){ int w=mx+l; for(l+=mx-1,r+=mx+1;r-l!=1;l>>=1,r>>=1){ if(~l&1&&t1[l+1]<t1[w])w=l+1; if(r&1&&t1[r-1]<t1[w])w=r-1; } for(;w<mx;w=w<<1^(t1[w<<1^1]==t1[w])); return w-mx; } int gmx(int l,int r){ int w=mx+l; for(l+=mx-1,r+=mx+1;r-l!=1;l>>=1,r>>=1){ if(~l&1&&t0[l+1]>t0[w])w=l+1; if(r&1&&t0[r-1]>t0[w])w=r-1; } for(;w<mx;w=w<<1^(t0[w<<1^1]==t0[w])); return w-mx; } int ins(int x,int y){ int p=gr(x),pe=pv_empty(p); if(pe){ flow(x,pe); set_(pe,2); e1[x].insert(y); upd1(x); return y; }else{ int z=gmn(1,p),zv=t1[mx+z]; if(zv<y){ flow(x,z); e1[x].insert(y); e1[z].erase(e1[z].find(zv)); e0[z].insert(zv); upd1(x),upd1(z),upd0(z); return y-zv; }else{ e0[x].insert(y); upd0(x); return 0; } } } int del(int x,int y){ if((it=e0[x].find(y))!=e0[x].end()){ e0[x].erase(it); upd0(x); return 0; }else{ e1[x].erase(e1[x].find(y)); upd1(x); int p=gl(x),z=gmx(p,n),zv=t0[mx+z]; if(zv>=0){ flow(z,x); e1[z].insert(zv); e0[z].erase(e0[z].find(zv)); upd1(z),upd0(z); return zv-y; } int pf=nx_full(p); flow(pf,x); set_(pf,1); return -y; } } int main(){ n=_(); rt=build(0,n); for(mx=1;mx<n+5;mx<<=1); for(int i=0;i<mx*2;++i)t1[i]=inf,t0[i]=-inf,em[i]=1; for(qp=_();qp;--qp){ int o=_(),a=_(),b=_(); printf("%lld\n",ans+=o==1920?ins(a,b):del(a,b)); } return 0; }