BZOJ1503[NOI2004]郁闷的出纳员——treap
OIER公司是一家大型專業化軟件公司,有著數以萬計的員工。作為一名出納員,我的任務之一便是統計每位員工的工資。這本來是一份不錯的工作,但是令人郁悶的是,我們的老板反復無常,經常調整員工的工資。如果他心情好,就可能把每位員工的工資加上一個相同的量。反之,如果心情不好,就可能把他們的工資扣除一個相同的量。我真不知道除了調工資他還做什么其它事情。
工資的頻繁調整很讓員工反感,尤其是集體扣除工資的時候,一旦某位員工發現自己的工資已經低于了合同規定的工資下界,他就會立刻氣憤地離開公司,并且再也不會回來了。每位員工的工資下界都是統一規定的。每當一個人離開公司,我就要從電腦中把他的工資檔案刪去,同樣,每當公司招聘了一位新員工,我就得為他新建一個工資檔案。
老板經常到我這邊來詢問工資情況,他并不問具體某位員工的工資情況,而是問現在工資第k多的員工拿多少工資。每當這時,我就不得不對數萬個員工進行一次漫長的排序,然后告訴他答案。
好了,現在你已經對我的工作了解不少了。正如你猜的那樣,我想請你編一個工資統計程序。怎么樣,不是很困難吧?
如果某個員工的初始工資低于最低工資標準,那么將不計入最后的答案內
輸入格式:
第一行有兩個非負整數n和min。n表示下面有多少條命令,min表示工資下界。
接下來的n行,每行表示一條命令。命令可以是以下四種之一:
名稱 格式 作用
I命令 I_k 新建一個工資檔案,初始工資為k。如果某員工的初始工資低于工資下界,他將立刻離開公司。
A命令 A_k 把每位員工的工資加上k
S命令 S_k 把每位員工的工資扣除k
F命令 F_k 查詢第k多的工資
_(下劃線)表示一個空格,I命令、A命令、S命令中的k是一個非負整數,F命令中的k是一個正整數。
在初始時,可以認為公司里一個員工也沒有。
輸出格式:
輸出文件的行數為F命令的條數加一。
對于每條F命令,你的程序要輸出一行,僅包含一個整數,為當前工資第k多的員工所拿的工資數,如果k大于目前員工的數目,則輸出-1。
輸出文件的最后一行包含一個整數,為離開公司的員工的總數。
輸入樣例#1:? 9 10 I 60 I 70 S 50 F 2 I 30 S 15 A 5 F 1 F 2 輸出樣例#1:? 10 20 -1 2說明
I命令的條數不超過100000
A命令和S命令的總條數不超過100
F命令的條數不超過100000
每次工資調整的調整量不超過1000
新員工的工資不超過100000
這道題是一道經典的平衡樹練習題,題中一共有四種操作:插入,查詢,修改(上調和下降)。
這里面唯一和一般的treap不一樣的操作就是修改,如果每一次都把每個數加上或減掉一個值顯然是不行的,但我們發現每次修改都是對全體修改,那么我們就可以不進行修改,相對的把工資下界調整,這樣也就相當于修改了每個員工的工資。
但是如果在某次漲工資之后來了一名員工,他并沒有趕上漲工資,如果他的工資大于初始工資下界(這樣才能進來)但卻小于當前工資下界,那么下一次降工資后他本來不會跳槽(下降之后仍大于初始工資下界),卻因為小于當前工資下界,那他到底會不會跳槽呢?依據題意是不會的,但如果按上述做法就是會跳槽的。那么就要在他剛進公司時我們要先給他加上之前漲的工資(使他工資一定大于當前工資下界),在查詢到他時再減掉就可以了。
工資下降相當于工資下界上調,這樣就有可能有人會跳槽,因為I命令不超過10^5,樹中最多不會超過10^5個節點,刪除點個數也不會超過這些,所以暴力刪除就好。
如果查前驅函數是void函數要記得每次查詢之后把answer歸零。
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<ctime> #include<cstring> using namespace std; int r[100010]; int v[100010]; int w[100010]; int ls[100010]; int rs[100010]; int size[100010]; int tot; int root; int n,m; int del; int mini; int x; char a[10]; int answer; int ans; void up(int x) {size[x]=size[rs[x]]+size[ls[x]]+w[x]; } void rturn(int &x) {int t;t=ls[x];ls[x]=rs[t];rs[t]=x;size[t]=size[x];up(x);x=t; } void lturn(int &x) {int t;t=rs[x];rs[x]=ls[t];ls[t]=x;size[t]=size[x];up(x);x=t; } void insert_sum(int x,int &i) {if(!i){i=++tot;w[i]=size[i]=1;v[i]=x;r[i]=rand();return ;}size[i]++;if(x==v[i]){w[i]++;}else if(x>v[i]){insert_sum(x,rs[i]);if(r[rs[i]]<r[i]){lturn(i);}}else{insert_sum(x,ls[i]);if(r[ls[i]]<r[i]) {rturn(i);}}return ; } void delete_sum(int x,int &i) {if(i==0){return ;}if(v[i]==x){if(w[i]>1){w[i]--;size[i]--;return ;}if((ls[i]*rs[i])==0){i=ls[i]+rs[i];}else if(r[ls[i]]<r[rs[i]]){rturn(i);delete_sum(x,i);}else{lturn(i);delete_sum(x,i);}return ;}size[i]--;if(v[i]<x){delete_sum(x,rs[i]);}else{delete_sum(x,ls[i]);}return ; } int ask_sum(int x,int i) {if(i==0){return 0;}if(x>size[ls[i]]+w[i]){return ask_sum(x-size[ls[i]]-w[i],rs[i]);}else if(size[ls[i]]>=x){return ask_sum(x,ls[i]);}else{return v[i];} } void ask_front(int x,int i) {if(i==0){return ;}if(v[i]<x){answer=i;ask_front(x,rs[i]);return ;}else{ask_front(x,ls[i]);return ;}return ; } int main() {srand(12378);scanf("%d%d",&n,&m);mini=m;for(int i=1;i<=n;i++){scanf("%s",a+1);scanf("%d",&x);if(a[1]=='I'){if(x>=mini){insert_sum(x-del,root);}}else if(a[1]=='A'){m-=x;del+=x;}else if(a[1]=='S'){m+=x;del-=x;answer=0;ask_front(m,root);while(answer!=0){delete_sum(v[answer],root);ans++;answer=0;ask_front(m,root);}}else if(a[1]=='F'){if(size[root]-x+1>0){printf("%d\n",ask_sum(size[root]-x+1,root)+del);}else{printf("-1\n");}}}printf("%d",ans); }轉載于:https://www.cnblogs.com/Khada-Jhin/p/8987211.html
總結
以上是生活随笔為你收集整理的BZOJ1503[NOI2004]郁闷的出纳员——treap的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Kafka C++客户端库librdka
- 下一篇: Python基础——正则2(0503)