bzoj 1503: [NOI2004]郁闷的出纳员
Description
OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。
工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。
老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。
好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?
如果某个员工的初始工资低于最低工资标准,那么将不计入最后的答案内
solution
正解:平衡树
我们维护一个全局变量\(f\),为之前扣除量之和,每一次扣除我们把下界加上k,并把小于下界的都删除,\(split\)一下前几个即可,每次插入的时候,初始工资要加上\(f\),并且离开的人数总和不算一开始就离开的
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#define RG register
#define il inline
#define iter iterator
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=100005;
typedef long long ll;
int Q,lim,ch[N][2],key[N],sz[N],v[N],rt,cnt=0,lazy[N],f=0;
inline void upd(int x){if(x)sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
inline void down(int x){
if(!x || !lazy[x])return ;
int ls=ch[x][0],rs=ch[x][1],k=lazy[x];
if(ls)v[ls]+=k,lazy[ls]+=k;
if(rs)v[rs]+=k,lazy[rs]+=k;
lazy[x]=0;
}
inline void split(int x,int k,int &a,int &b){
if(!k){a=0;b=x;return ;}
down(x);
int l=ch[x][0],r=ch[x][1];
if(sz[l]==k)ch[x][0]=0,a=l,b=x;
else if(sz[l]+1==k)ch[x][1]=0,a=x,b=r;
else if(sz[l]>k)split(l,k,a,ch[x][0]),b=x;
else split(r,k-sz[l]-1,ch[x][1],b),a=x;
upd(x);
}
inline int merge(int x,int y){
if(!x || !y)return x+y;
down(x);down(y);
if(key[x]>key[y]){
ch[x][1]=merge(ch[x][1],y);
upd(x);
return x;
}
else{
ch[y][0]=merge(x,ch[y][0]);
upd(y);
return y;
}
}
inline int rank(int k){
int ret=1,x=rt;
while(x){
down(x);
if(k<=v[x])x=ch[x][0];
else ret+=sz[ch[x][0]]+1,x=ch[x][1];
}
return ret;
}
inline void ins(int x){
if(x<lim)return ;
int l,r;
v[++cnt]=x;key[cnt]=rand();sz[cnt]=1;
split(rt,rank(x)-1,l,r);
rt=merge(merge(l,cnt),r);
}
inline void Delet(int k){int l;split(rt,k,l,rt);}
inline int kth(int k){
int x=rt,sum;
while(x){
down(x);
sum=sz[ch[x][1]];
if(sum==k-1)return v[x];
if(sum>=k)x=ch[x][1];
else k-=sum+1,x=ch[x][0];
}return -1;
}
void work()
{
int x,y,ans=0;char S[3];
scanf("%d%d",&Q,&lim);
while(Q--){
scanf("%s%d",S,&x);
if(S[0]=='I')ins(x+f);
else if(S[0]=='A')v[rt]+=x,lazy[rt]+=x;
else if(S[0]=='S'){
f+=x,lim+=x;
y=rank(lim)-1;
if(y>=1)Delet(y),ans+=y;
}
else y=kth(x),printf("%d\n",y==-1?-1:y-f);
}
printf("%d\n",ans);
}
int main()
{
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
work();
return 0;
}