刷題總結——郁悶的出納員(bzoj1503)
題目:
題目背景
NOI2004 DAY1 T1
題目描述
OIER 公司是一家大型專業化軟件公司,有著數以萬計的員工。作為一名出納員,我的任務之一便是統計每位員工的工資。這本來是一份不錯的工作,但是令人郁悶的是,我們的老板反復無常,經常調整員工的工資。如果他心情好,就可能把每位員工的工資加上一個相同的量。反之,如果心情不好,就可能把他們的工資扣除一個相同的量。我真不知道除了調工資他還做什麽其它事情。
工資的頻繁調整很讓員工反感,尤其是集體扣除工資的時候,一旦某位員工發現自己的工資已經低於了合同規定的工資下界,他就會立刻氣憤地離開公司,並且再也不會回來了。每位員工的工資下界都是統一規定的。每當一個人離開公司,我就要從電腦中把他的工資檔案刪去,同樣,每當公司招聘了一位新員工,我就得為他新建一個工資檔案。
老板經常到我這邊來詢問工資情況,他並不問具體某位員工的工資情況,而是問現在工資第 k 多的員工拿多少工資。每當這時,我就不得不對數萬個員工進行一次漫長的排序,然後告訴他答案。
好了,現在你已經對我的工作了解不少了。正如你猜的那樣,我想請你編一個工資統計程序。怎麽樣,不是很困難吧?
輸入格式
第一行有兩個非負整數 n 和 min 。n 表示下面有多少條命令,min 表示工資下界。
接下來的 n 行,每行表示一條命令。命令可以是以下四種之一:
“下劃線( _ )”表示一個空格,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
輸出
10
20
-1
2
備註
【數據範圍】
I 命令的條數不超過 100000
A 命令和 S 命令的總條數不超過 100
F 命令的條數不超過 100000
每次工資調整的調整量不超過 1000
新員工的工資不超過 100000
【評分方法】
對於每個測試點,如果你輸出文件的行數不正確,或者輸出文件中含有非法字符,得分為 0 。
否則你的得分按如下方法計算:
- 如果對於所有的 F 命令,你都輸出了正確的答案,並且最後輸出的離開公司的人數也是正確的,你將得到 10 分;
- 如果你只對所有的 F 命令輸出了正確答案,得 6 分;
- 如果只有離開公司的人數是正確的,得 4 分;否則得 0 分。
題解:
重要的事情先說下:
仔細審題!!!!!
做的時候以為加入公司就走的員工是要算入總數的·····結果tm不算·····感覺題目也沒說清楚啊···
其余的就是splay的基本操作了···另外這道題有個很巧妙的地方是記錄一個sum維護修改公司的總和,並根據sum不是直接修改所有員工的工資數,而是修改加入的人的工資數和每次判斷離開公司的人時修改minn(具體看代碼)····,這樣就能節約復雜度了···
代碼:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int N=3e5+5; int val[N],father[N],cnt[N],son[N][2],size[N],root,tot; int n,a,minn,totl=0,sum=0; long long totcut=0; char s[5]; inline int R() { char c;int f=0; for(c=getchar();c<‘0‘||c>‘9‘;c=getchar()); for(;c<=‘9‘&&c>=‘0‘;c=getchar()) f=(f<<3)+(f<<1)+c-‘0‘; return f; } inline void clear(int now) { size[now]=son[now][0]=son[now][1]=val[now]=cnt[now]=father[now]=0; } inline void update(int now) { if(now) { size[now]=cnt[now]; if(son[now][0]) size[now]+=size[son[now][0]]; if(son[now][1]) size[now]+=size[son[now][1]]; } } inline int get(int a) { return son[father[a]][1]==a; } inline void rotate(int now) { int fa=father[now],ofa=father[fa],which=get(now); son[fa][which]=son[now][which^1],father[son[fa][which]]=fa; son[now][which^1]=fa,father[fa]=now,father[now]=ofa; if(ofa) son[ofa][son[ofa][1]==fa]=now; update(fa),update(now); } inline void splay(int now) { while(father[now]) { if(father[father[now]]) rotate(get(now)==get(father[now])?father[now]:now); rotate(now); } root=now; } inline void insert(int x) { int now=root,last=0; while(true) { if(!now) { now=++tot;size[now]=cnt[now]=1;father[now]=last;val[now]=x; son[last][val[now]>val[last]]=now;update(last);splay(now); break; } if(val[now]==x) { cnt[now]++;update(now);update(last);splay(now); break; } last=now;now=son[now][x>val[now]]; } } inline int findx(int x) { int now=root; while(true) { if(x<=size[son[now][0]]) now=son[now][0]; else { int temp=size[son[now][0]]+cnt[now]; if(x<=temp) return val[now]; x-=temp;now=son[now][1]; } } } inline int Delete() { int temp=size[son[root][0]]+cnt[root];int oldroot=root; root=son[oldroot][1];father[root]=0; clear(oldroot); return temp; } int main() { //freopen("a.in","r",stdin); n=R(),minn=R(); while(n--) { scanf("%s%d",s,&a); if(s[0]==‘I‘) { if(a-sum>(minn-sum-1)) insert(a-sum),totl++; } if(s[0]==‘A‘) sum+=a; if(s[0]==‘S‘) sum-=a; if(s[0]==‘F‘) { if(totl<a) cout<<"-1"<<endl; else { int ans=findx(totl-a+1); cout<<ans+sum<<endl; } } int limit=minn-sum-1;insert(limit); int temp=Delete(); totcut+=(long long)(temp-1); totl=totl-temp+1; } cout<<totcut<<endl; return 0; }
刷題總結——郁悶的出納員(bzoj1503)