bzoj1503 郁悶的出納員(平衡樹,思維)
阿新 • • 發佈:2018-12-22
pre queue get turn fin 怎麽 for out 刪掉
題目大意:
現在有n個操作和一個最低限度m
\(I\)命令\(I\ k\)新建一個工資檔案,初始工資為k。
\(A\)命令$A k $把每位員工的工資加上k
\(S\)命令$S k $把每位員工的工資扣除k
\(F\)命令$ F k\(查詢第k多的工資 (如果當前的員工總數不夠k,就輸出\)-1$)
其中\(n \le 100000\)
最後還要輸出最終離開了多少個員工
需要註意的是 ,如果某員工的初始工資低於工資下界,他將立刻離開公司!!!!
一看這個題,就感覺是個\(splay\)了
不過emmmm 這個整體加和整體減應該怎麽弄呢
我們考慮維護一個整體的變化值\(tmp\)
那麽對於splay中的每個元素,它的實際權值就是\(x+tmp\)
這麽來說
對於\(I\)操作,如果它的權值\(>\)m,則\(insert(x-tmp)\)
對於\(A\)操作,直接\(tmp+=x\)
對於\(S\)操作,我們讓\(tmp-=x\),並且判斷有沒有需要退出的點(就是直接將\(-inf\)轉到\(root\),然後把\(min1-tmp-1\)的後繼轉到root的右兒子,刪掉左兒子)這樣做的原因是避免哨兵被刪掉
對於\(F\)操作,那就直接返回第k大,然後\(+tmp\)就可以
代碼還是有很多細節的,比如要維護當前平衡樹中有幾個元素,事先加入哨兵之類的,直接看代碼吧
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<map> #include<queue> #include<vector> using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch==‘-‘) f=-1;ch=getchar();} while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();} return x*f; } const int maxn = 1e6+1e2; int ch[maxn][4]; int val[maxn],sz[maxn],size; int fa[maxn]; int cnt[maxn]; int n,m,ymh,root,min1; int tot; int num=0; int ans; int son(int x) { if (x==ch[fa[x]][0]) return 0; else return 1; } void update(int x) { sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x]; } void rotate(int x) { int y=fa[x],z=fa[y]; int b=son(x),c=son(y); ch[z][c]=x; fa[x]=z; ch[y][b]=ch[x][!b]; fa[ch[x][!b]]=y; ch[x][!b]=y; fa[y]=x; update(y); update(x); } void splay(int x,int p) { while (fa[x]!=p) { int y=fa[x],z=fa[y]; if (z==p) rotate(x); else { if (son(x)==son(y)) { rotate(y); rotate(x); } else { rotate(x); rotate(x); } } } if (fa[x]==0) root=x; } int find_qq(int x) { int now = root,num=0; while (now) { if (val[now]<x) { num=now; now=ch[now][1]; } else now=ch[now][0]; } return num; } int find_hj(int x) { int now = root,num=0; while (now) { if (val[now]>x) { num=now; now=ch[now][0]; } else now=ch[now][1]; } return num; } void insert(int x) { tot++; int qq = find_qq(x); int hj = find_hj(x); splay(qq,0); splay(hj,qq); int y = ch[hj][0]; if (cnt[y]) { cnt[y]++; update(y); } else { ++size; ch[hj][0]=size; fa[size]=hj; val[size]=x; cnt[size]=1; sz[size]=1; //cout<<"gg11"<<endl; update(size); } } void delet(int x) { --tot; int qq = find_qq(x); int hj = find_hj(x); splay(qq,0); splay(hj,qq); int y = ch[hj][0]; if (cnt[y]>1) { cnt[y]--; update(y); } else { cnt[y]=0; fa[y]=0; ch[hj][0]=0; sz[y]=0; val[y]=0; } } int kth(int x) { int now = root; while (1) { if (x<=sz[ch[now][0]]) now=ch[now][0]; else{ if (x<=sz[ch[now][0]]+cnt[now]) return val[now]; x-=sz[ch[now][0]]+cnt[now]; now=ch[now][1]; } } } int add; int main() { size=2; val[1]=2e9; val[2]=-2e9; fa[2]=1; ch[1][0]=2; root=1; scanf("%d%d",&n,&min1); for (int i=1;i<=n;i++) { char s[10]; int x; scanf("%s",s+1); //cout<<size<<endl; x=read(); //cout<<x<<endl; if (s[1]==‘A‘) { ymh+=x; } if (s[1]==‘S‘) { ymh-=x; int hj = find_hj(min1-ymh-1); splay(2,0); splay(hj,2); int pos = ch[hj][0]; ans+=sz[pos]; tot-=sz[pos]; fa[pos]=0; ch[hj][0]=0; sz[pos]=0; cnt[pos]=0; /*if (tot==0) { size=2; val[1]=2e9; val[2]=-2e9; fa[2]=1; ch[1][0]=2; root=1; }*/ //cout<<ans; } if (s[1]==‘I‘) { if (x<min1) continue; //cout<<"gg"<<endl; insert(x-ymh); } if (s[1]==‘F‘) { //cout<<tot<<endl; if (x>tot) printf("-1\n"); else printf("%d\n",kth(tot-x+1)+ymh); } //cout<<tot<<endl; } cout<<ans; return 0; }
bzoj1503 郁悶的出納員(平衡樹,思維)