[BZOJ1503] [NOI2004] 郁闷的出纳员 (treap)
Posted CtrlCV
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1503] [NOI2004] 郁闷的出纳员 (treap)相关的知识,希望对你有一定的参考价值。
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
Source
Solution
因为每一次的加减工资是对全体员工进行的,所以我们可以对整体打一个$lazy$标记,表示工资的变化情况
$treap$里记录的是每个人的实际工资$x$减去$lazy$后的值
那么,对于一个新来的人,他的工资的相对值就是初始工资$k$减$lazy$的值
查询操作由于要查第$k$大,为了方便,可以从大到小维护$treap$,然后就没什么难点了
有一个极坑的点:如果一个人初始工资低于$min$,这个人不算做离开公司!!!答案里不算这个人!!!
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct treap 4 { 5 int l, r, siz, pri, key, val; 6 }a[100005]; 7 int ans, ptot; 8 9 void push_up(int k) 10 { 11 a[k].siz = a[a[k].l].siz + a[a[k].r].siz + a[k].val; 12 } 13 14 void lturn(int &k) 15 { 16 int tmp = a[k].r; 17 a[k].r = a[tmp].l, a[tmp].l = k; 18 a[tmp].siz = a[k].siz, push_up(k), k = tmp; 19 } 20 21 void rturn(int &k) 22 { 23 int tmp = a[k].l; 24 a[k].l = a[tmp].r, a[tmp].r = k; 25 a[tmp].siz = a[k].siz, push_up(k), k = tmp; 26 } 27 28 void insert(int &k, int x) 29 { 30 if(!k) 31 { 32 k = ++ptot, a[k].siz = a[k].val = 1; 33 a[k].key = x, a[k].pri = rand(); 34 return; 35 } 36 ++a[k].siz; 37 if(x == a[k].key) ++a[k].val; 38 else if(x > a[k].key) 39 { 40 insert(a[k].l, x); 41 if(a[a[k].l].pri > a[k].pri) rturn(k); 42 } 43 else 44 { 45 insert(a[k].r, x); 46 if(a[a[k].r].pri > a[k].pri) lturn(k); 47 } 48 } 49 50 void del(int &k, int x) 51 { 52 if(!k) return; 53 if(x <= a[k].key) del(a[k].r, x), push_up(k); 54 else 55 { 56 ans += a[a[k].r].siz + a[k].val; 57 a[k].r = 0, k = a[k].l; 58 del(k, x), push_up(k); 59 } 60 } 61 62 int find_kth(int k, int x) 63 { 64 if(!k) return -1; 65 if(x <= a[a[k].l].siz) return find_kth(a[k].l, x); 66 if(x <= a[a[k].l].siz + a[k].val) return k; 67 return find_kth(a[k].r, x - a[a[k].l].siz - a[k].val); 68 } 69 70 int main() 71 { 72 int n, m, k, root = 0, lazy = 0; 73 char op[5]; 74 scanf("%d%d", &n, &m); 75 srand(n); 76 while(n--) 77 { 78 scanf("%s%d", op, &k); 79 if(op[0] == \'I\') 80 { 81 if(k < m) continue; 82 insert(root, k - lazy); 83 } 84 if(op[0] == \'A\') lazy += k; 85 if(op[0] == \'S\') 86 { 87 lazy -= k; 88 del(root, m - lazy); 89 } 90 if(op[0] == \'F\') 91 { 92 k = find_kth(root, k); 93 printf("%d\\n", ~k ? a[k].key + lazy : -1); 94 } 95 } 96 printf("%d\\n", ans); 97 return 0; 98 }
以上是关于[BZOJ1503] [NOI2004] 郁闷的出纳员 (treap)的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1503: [NOI2004]郁闷的出纳员 平衡树