[BZOJ1503] [NOI2004] 郁闷的出纳员 (treap)

Posted CtrlCV

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1503] [NOI2004] 郁闷的出纳员 (treap)相关的知识,希望对你有一定的参考价值。

Description

  OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?

Input

Output

  输出文件的行数为F命令的条数加一。对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。输出文件的最后一行包含一个整数,为离开公司的员工的总数。

Sample Input

9 10
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2

Sample Output

10
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 }
View Code

 

以上是关于[BZOJ1503] [NOI2004] 郁闷的出纳员 (treap)的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 1503: [NOI2004]郁闷的出纳员

bzoj1503: [NOI2004]郁闷的出纳员

bzoj 1503: [NOI2004]郁闷的出纳员 平衡树

BZOJ 1503NOI 2004郁闷的出纳员

[BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap

bzoj 1503: [NOI2004]郁闷的出纳员 -- 权值线段树