bzoj:1503[NOI2004]郁闷的出纳员
Description
OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?
Input
Output
输出文件的行数为F命令的条数加一。对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。输出文件的最后一行包含一个整数,为离开公司的员工的总数。
Sample Input
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2
Sample Output
20
-1
2
HINT
I命令的条数不超过100000 A命令和S命令的总条数不超过100 F命令的条数不超过100000 每次工资调整的调整量不超过1000 新员工的工资不超过100000
题解
由于加减工资是对所有人有效,所以可以通过设置一个基准值,使得实际工资=基准值+相对工资,加减工资时只用改变基准即可。记得每次减工资以后看一看有几个人离开并记录。
因为要找第k大的数,所以左子树>根节点>右子树(节点权值),这样操作比较方便。
删除操作比较简单,找到k大于的那一部分,将其连同子树全部删掉,然后把另外大于等于它的一边做根即可。
(特别鸣谢wahaha大佬%%%)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cstdlib> 5 #define maxn 100010 6 using namespace std; 7 int n,root,ans,Std,cnt; 8 struct treap{ 9 int lc,rc,key,pri,siz,val; 10 }a[maxn]; 11 void pushup(int o){a[o].siz=a[a[o].lc].siz+a[a[o].rc].siz+a[o].val;} 12 void lturn(int &o) 13 { 14 int t=a[o].rc; 15 a[o].rc=a[t].lc; 16 a[t].lc=o; 17 a[t].siz=a[o].siz; 18 pushup(o); 19 o=t; 20 return ; 21 } 22 void rturn(int &o) 23 { 24 int t=a[o].lc; 25 a[o].lc=a[t].rc; 26 a[t].rc=o; 27 a[t].siz=a[o].siz; 28 pushup(o); 29 o=t; 30 return ; 31 } 32 void insert(int &o,int x) 33 { 34 if(!o) 35 { 36 o=++cnt; 37 a[o]=(treap){0,0,x,rand(),1,1}; 38 return ; 39 } 40 a[o].siz++; 41 if(a[o].key==x) a[o].val++; 42 else if(x>a[o].key) 43 { 44 insert(a[o].lc,x); 45 if(a[a[o].lc].pri>a[o].pri)rturn(o); 46 } 47 else 48 { 49 insert(a[o].rc,x); 50 if(a[a[o].rc].pri>a[o].pri)lturn(o); 51 } 52 return ; 53 } 54 void del(int &o,int x) 55 { 56 if(!o)return ; 57 if(x<=a[o].key) 58 { 59 del(a[o].rc,x); 60 pushup(o); 61 } 62 else 63 { 64 ans+=a[a[o].rc].siz+a[o].val; 65 a[o].rc=0; 66 o=a[o].lc; 67 del(o,x); 68 pushup(o); 69 } 70 return ; 71 } 72 int que_num(int o,int x) 73 { 74 if(!o)return 0; 75 if(x<=a[a[o].lc].siz)return que_num(a[o].lc,x); 76 if(x<=a[a[o].lc].siz+a[o].val)return o; 77 return que_num(a[o].rc,x-a[o].val-a[a[o].lc].siz); 78 } 79 int main() 80 { 81 int lim; 82 scanf("%d%d",&n,&lim); 83 srand(n); 84 char str[3];int k; 85 for(int i=1 ; i<=n ; ++i ) 86 { 87 scanf("%s%d",str,&k); 88 if(str[0]=='I') 89 { 90 if(k>=lim)insert(root,k-Std); 91 } 92 else if(str[0]=='A')Std+=k; 93 else if(str[0]=='S') 94 { 95 Std-=k; 96 del(root,lim-Std); 97 } 98 if(str[0]=='F') 99 { 100 k=que_num(root,k); 101 if(!k)printf("-1\n"); 102 else printf("%d\n",a[k].key+Std); 103 } 104 } 105 printf("%d",ans); 106 return 0; 107 }