首页 > 代码库 > [BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap

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

1503: [NOI2004]郁闷的出纳员

Time Limit: 5 Sec  Memory Limit: 64 MB

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

 

题解:

当时想拿这道题学splay的结果把自己调死了……今天又回来看这道题感觉很清晰……

我们考虑对于一个节点,在它插入以前,工资调整它不会受到影响,插入以后才被影响

但是我们又不能实时的更新每个节点的值,所以我们考虑用一个变量来差分:

用tmp变量记录到目前为止的工资变动,如果我们要插入一个本来值为val的节点,我们就插入一个值val-tmp

而查询的时候,节点的实际值是val+tmp‘。tmp‘-tmp就是它从插入开始到现在的变化工资,所以这样我们就可以正确的计算了。

剩下的实现就很简单了,代码见下:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <ctime>
 4 #include <iostream>
 5 #include <cstdlib>
 6 using namespace std;
 7 int minn,ans;
 8 struct Treap
 9 {
10     Treap *ch[2];
11     int size,val,key;
12     Treap(){val=size=0;key=rand();ch[1]=ch[0]=NULL;}
13     inline void update()
14         {size=ch[0]->size+ch[1]->size+1;}
15 }*null=new Treap,*root=null;
16 typedef pair<Treap*,Treap*> D;
17 inline Treap* newTreap(int v)
18 {
19     Treap *o=new Treap();
20     o->ch[0]=o->ch[1]=null;
21     o->size=1;o->val=v;
22     return o;
23 }
24 Treap* merge(Treap* a,Treap* b)
25 {
26     if(a==null)return b;
27     if(b==null)return a;
28     if(a->key < b->key)
29         {a->ch[1]=merge(a->ch[1],b);a->update();return a;}
30     else
31         {b->ch[0]=merge(a,b->ch[0]);b->update();return b;}
32 }
33 D split(Treap *o,int k)
34 {
35     if(o==null)return D(null,null);
36     D y;
37     if(o->ch[0]->size >= k)
38         {y=split(o->ch[0],k);o->ch[0]=y.second;o->update();y.second=o;}
39     else
40         {y=split(o->ch[1],k-o->ch[0]->size-1);o->ch[1]=y.first;o->update();y.first=o;}
41     return y;
42 }
43 int getrank(Treap *o,int val)
44 {
45     if(o==null)return 0;
46     return o->val >= val?getrank(o->ch[0],val):getrank(o->ch[1],val)+o->ch[0]->size+1;
47 }
48 inline int getval(int rank)
49 {
50     D x=split(root,rank-1);
51     D y=split(x.second,1);
52     int ans=y.first->val;
53     root=merge(merge(x.first,y.first),y.second);
54     return ans;
55 }
56 inline void insert(int val)
57 {
58     int k=getrank(root,val);
59     D x=split(root,k);
60     Treap *o=newTreap(val);
61     root=merge(merge(x.first,o),x.second);
62 }
63 inline void erase()
64 {
65     D x=split(root,1);
66     root=x.second;ans++;
67 }
68 int main()
69 {
70     int m,x,tmp=0;char s[5];
71     scanf("%d%d",&m,&minn);
72     while(m--)
73     {
74         scanf("%s%d",s,&x);
75         switch(s[0])
76         {
77             case I:if(x>=minn)insert(x-tmp);break;
78             case F:
79             {
80                 if(root==null||root->size<x)printf("-1\n");
81                 else printf("%d\n",getval(root->size-x+1)+tmp);
82                 break;
83             }
84             case A:tmp+=x;break;
85             case S:
86                 {tmp-=x;while(root!=null&&getval(1)+tmp<minn)erase();break;}
87         }
88     }
89     printf("%d",ans);
90 }

 

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