题目:BZOJ1503、洛谷P1486、codevs1286、Vijos P1507。
题目大意:叫你编一个工资统计程序,具体操作见题目。
解题思路:建一棵权值线段树,保存每种工资的数量,由于工资可能有负,可以先对每个工资加上200000,然后进行处理。对于加减工资操作,直接用个变量储存工资变化即可。减工资时相当于区间赋0操作。查询时先把他转化为求第k小,再查询即可。
C++ Code:
#include<cstdio> #include<cstring> using namespace std; int m,down,bh,k,ans; const int n=404000; int d[4005050]; char s[3]; void add(int l,int r,int o,int p){ if(l!=r) if(d[o]==0)d[o<<1]=d[o<<1|1]=0; ++d[o]; if(l==r)return; int mid=l+r>>1; if(p<=mid)add(l,mid,o<<1,p);else add(mid+1,r,o<<1|1,p); } void del(int l,int r,int o,int p){ if(d[o]==0)d[o<<1]=d[o<<1|1]=0; if(r<=p){ ans+=d[o]; d[o]=0; return; } int mid=l+r>>1; del(l,mid,o<<1,p); if(mid<p)del(mid+1,r,o<<1|1,p); d[o]=d[o<<1]+d[o<<1|1]; } int query(int l,int r,int o,int k){ if(d[o]==0)d[o<<1]=d[o<<1|1]=0; if(l==r)return l; int mid=l+r>>1; if(d[o<<1]>=k)return query(l,mid,o<<1,k); else return query(mid+1,r,o<<1|1,k-d[o<<1]); } int main(){ scanf("%d%d",&m,&down); down+=200000; memset(d,0,sizeof d); bh=0; ans=0; while(m--){ scanf("%s%d",s,&k); switch(s[0]){ case'I': k+=200000; if(k>=down)add(1,n,1,k-bh); break; case'A': bh+=k; break; case'S': bh-=k; del(1,n,1,down-bh-1); break; case'F': k=d[1]-k+1; if(k<1)puts("-1");else printf("%d ",query(1,n,1,k)+bh-200000); } } printf("%d ",ans); return 0; }