[BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap
Posted LadyLex
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap相关的知识,希望对你有一定的参考价值。
1503: [NOI2004]郁闷的出纳员
Time Limit: 5 Sec Memory Limit: 64 MBDescription
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
题解:
当时想拿这道题学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的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 1503: [NOI2004]郁闷的出纳员 平衡树