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

时间:2024-04-12 16:04:54

Description

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

Input

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

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$,这个人不算做离开公司!!!答案里不算这个人!!!

 #include <bits/stdc++.h>
using namespace std;
struct treap
{
int l, r, siz, pri, key, val;
}a[];
int ans, ptot; void push_up(int k)
{
a[k].siz = a[a[k].l].siz + a[a[k].r].siz + a[k].val;
} void lturn(int &k)
{
int tmp = a[k].r;
a[k].r = a[tmp].l, a[tmp].l = k;
a[tmp].siz = a[k].siz, push_up(k), k = tmp;
} void rturn(int &k)
{
int tmp = a[k].l;
a[k].l = a[tmp].r, a[tmp].r = k;
a[tmp].siz = a[k].siz, push_up(k), k = tmp;
} void insert(int &k, int x)
{
if(!k)
{
k = ++ptot, a[k].siz = a[k].val = ;
a[k].key = x, a[k].pri = rand();
return;
}
++a[k].siz;
if(x == a[k].key) ++a[k].val;
else if(x > a[k].key)
{
insert(a[k].l, x);
if(a[a[k].l].pri > a[k].pri) rturn(k);
}
else
{
insert(a[k].r, x);
if(a[a[k].r].pri > a[k].pri) lturn(k);
}
} void del(int &k, int x)
{
if(!k) return;
if(x <= a[k].key) del(a[k].r, x), push_up(k);
else
{
ans += a[a[k].r].siz + a[k].val;
a[k].r = , k = a[k].l;
del(k, x), push_up(k);
}
} int find_kth(int k, int x)
{
if(!k) return -;
if(x <= a[a[k].l].siz) return find_kth(a[k].l, x);
if(x <= a[a[k].l].siz + a[k].val) return k;
return find_kth(a[k].r, x - a[a[k].l].siz - a[k].val);
} int main()
{
int n, m, k, root = , lazy = ;
char op[];
scanf("%d%d", &n, &m);
srand(n);
while(n--)
{
scanf("%s%d", op, &k);
if(op[] == 'I')
{
if(k < m) continue;
insert(root, k - lazy);
}
if(op[] == 'A') lazy += k;
if(op[] == 'S')
{
lazy -= k;
del(root, m - lazy);
}
if(op[] == 'F')
{
k = find_kth(root, k);
printf("%d\n", ~k ? a[k].key + lazy : -);
}
}
printf("%d\n", ans);
return ;
}