1. 程式人生 > >[BZOJ1503][NOI2004]郁悶的出納員 無旋Treap

[BZOJ1503][NOI2004]郁悶的出納員 無旋Treap

就會 lin ++ des 開始 不能 pan min 但是

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