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;
}

posted @ 2017-12-24 08:31  PIPIBoss  阅读(155)  评论(0编辑  收藏  举报