BZOJ1503 [NOI2004]郁闷的出纳员
AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1503
【我的感受】
这题郁闷了很久,因为discuss里讨论的问题和我都不是一个问题...
discuss里的当然是一大坑点啦,就是初始工资挂了的不算在最后踢出的人数中。
不过这个我倒是刚开始就这么打的...不过我一直超时啊超时啊...
终于要来了数据...额,原来是平衡树的性质都没怎么用...根本没转几次啊,然后数据就特意卡了这个,连续添加递增工资的人[变成了链]
那我就随机转一转好了,然后不知道为什么不能srand(time(0)),反正这样就会RE,于是干脆不加随机种子了,终于搞定了...
【分析】
这题我的思路大概是这样的:
1.因为不管是加工资还是减工资还是加成员还是问第k大,都和数据的数值有关而与顺序无关,于是按数值大小建立二叉树
2.这题和平常做的+tag的题只有一种区别,就是删除和减工资一起执行了。于是需要将会被删掉的人事先找出来,即 工资<最低工资+扣减工资 的人,这当然是一颗子树啦,删掉就好。
3.其它的操作就和之前的一样了,因为每次的增工资和减工资都是对所有人进行,所以相对大小不会变,下次如果将区间增加值...那就麻烦大了[怎么做呢?我自然是想不到了...]
#include<cstdio> #include<ctime> #include<cstring> #include<cstdlib> #include<algorithm> using namespace std; inline int in(){ int x=0;char ch=getchar(); while(ch>'9' || ch<'0') ch=getchar(); while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar(); return x; } const int maxn=100010; struct Node{ int f,ch[2]; int sz,ct; int dt,pt; }s[maxn]; int m,Min,n,rt; void push_down(int x){ if(!s[x].pt) return; if(s[x].ch[0]) s[s[x].ch[0]].dt+=s[x].pt,s[s[x].ch[0]].pt+=s[x].pt; if(s[x].ch[1]) s[s[x].ch[1]].dt+=s[x].pt,s[s[x].ch[1]].pt+=s[x].pt; s[x].pt=0; } void update(int x){ s[x].sz=s[s[x].ch[0]].sz+s[s[x].ch[1]].sz+s[x].ct; } int Find(int k){ int p=rt; if(s[rt].sz<k || k<=0) return -1; while(p){ push_down(p); if(k<=s[s[p].ch[0]].sz) p=s[p].ch[0]; else{ k-=s[s[p].ch[0]].sz; if(k<=s[p].ct) return p; k-=s[p].ct;p=s[p].ch[1]; } } } void Rotate(int x,int k){ int y=s[x].f;s[x].f=s[y].f; if(s[y].f){ if(s[s[y].f].ch[0]==y) s[s[y].f].ch[0]=x;else s[s[y].f].ch[1]=x;} s[y].ch[k]=s[x].ch[k^1]; if(s[x].ch[k^1]) s[s[x].ch[k^1]].f=y; s[y].f=x,s[x].ch[k^1]=y; update(y),update(x); } void Splay(int x,int gf){ int y; while(s[x].f!=gf){ y=s[x].f; if(s[y].f==gf){ if(x==s[y].ch[0]) Rotate(x,0); else Rotate(x,1);} else{ int z=s[y].f; if(y==s[z].ch[0]){ if(x==s[y].ch[0]) Rotate(y,0),Rotate(x,0);else Rotate(x,1),Rotate(x,0);} else{ if(x==s[y].ch[1]) Rotate(y,1),Rotate(x,1);else Rotate(x,0),Rotate(x,1);} } } if(!gf) rt=x; } void Insert(int x){ if(x<Min) return; if(!rt){s[++n].dt=x;s[n].sz=1;rt=n,s[n].ct=1;return;} int p=rt; while(p){ s[p].sz++; push_down(p); if(s[p].dt<x){ if(s[p].ch[1]) p=s[p].ch[1]; else{ s[p].ch[1]=++n,s[n].dt=x,s[n].sz=1,s[n].f=p,s[n].ct=1;break; } } else if(s[p].dt>x){ if(s[p].ch[0]) p=s[p].ch[0]; else{ s[p].ch[0]=++n,s[n].dt=x,s[n].sz=1,s[n].f=p,s[n].ct=1;break; } } else{ n++;s[p].ct++;return; } } if(rand()%100>80) Splay(n,0); } void Addition(int x){ s[rt].dt+=x,s[rt].pt+=x; } void Shorten(int x){ int p=rt,bye=Min+x,rec=-1; while(p){ push_down(p); if(s[p].dt<bye) rec=p,p=s[p].ch[1]; else p=s[p].ch[0]; } if(rec!=-1){ Splay(rec,0); rt=s[rec].ch[1],s[rt].f=0; if(rt) update(rt); } if(rt) s[rt].dt-=x,s[rt].pt-=x; } int Get_kth(int k){ int x=Find(s[rt].sz-k+1); if(x<0) return -1; if(rand()%100>80) Splay(x,0); return s[x].dt; } int main(){ #ifndef ONLINE_JUDGE freopen("1503.in","r",stdin); freopen("1503.out","w",stdout); #endif int k; char ord[2]; scanf("%d%d",&m,&Min); while(m--){ scanf("%s",ord);k=in(); if(ord[0]=='I') Insert(k); else if(ord[0]=='A') Addition(k); else if(ord[0]=='S') Shorten(k); else if(ord[0]=='F') printf("%d\n",Get_kth(k)); } printf("%d",n-s[rt].sz); return 0; }