被一道水题卡了一天……我真的好菜啊……
对于这题的‘A’和‘S’操作,我们没必要每次修改整个平衡树内的权值,而是转化成用一个变量t来表示当前所有员工的工资变动大小。
与之相对应的,插入操作就改成插入一个权值为k+t的人。
删除也非常简单,直接在整个平衡树中求k的后继,然后把k的后继旋转到根,显然当前根的左子树直接被舍弃。
询问就普普通通的搞一下就行了。
p.s.这题的细节较多,请各位大佬注意一下细节的处理。
附上AC代码:
#include <cstdio>
using namespace std;
const int N=1e5+10;
int n,m,x,size,rt,f[N],sz[N],w[N],ch[N][2],sum,t;
char s[10];
inline void updata(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
inline void rotate(int x){
int y=f[x],op=(ch[y][1]==x);
ch[y][op]=ch[x][op^1];
if (ch[x][op^1]) f[ch[x][op^1]]=y;
f[x]=f[y];
if (f[y]) ch[f[y]][ch[f[y]][1]==y]=x;
f[y]=x,ch[x][op^1]=y;
return updata(y),updata(x);
}
inline void splay(int x,int ed){
for (int fa=f[x]; fa!=ed; rotate(x),fa=f[x])
if (f[fa]!=ed) rotate((x==ch[fa][0])==(fa==ch[f[fa]][0])?fa:x);
if (ed==0) rt=x;
return;
}
inline void ist(int x){
int now=rt;
while (ch[now][w[now]<x]) now=ch[now][w[now]<x];
w[++size]=x,f[size]=now,ch[size][0]=ch[size][1]=0;
if (now) ch[now][w[now]<x]=size;
return splay(size,0);
}
inline int suc(int x,int k){
if (x==0) return 0;
if (w[x]>=k){
int t=suc(ch[x][0],k);
if (t==0) return x;
return t;
}
return suc(ch[x][1],k);
}
inline int query(int x,int k){
if (x==0||k<0) return -1;
if (sz[ch[x][1]]+1==k) return w[x]+t;
if (sz[ch[x][1]]+1>k) return query(ch[x][1],k);
return query(ch[x][0],k-sz[ch[x][1]]-1);
}
int main(void){
for (scanf("%d%d",&n,&m); n; --n){
scanf("%s%d",s,&x);
switch (s[0]){
case 'I': if (x>=m) ++sum,ist(x-t); break;
case 'A': t+=x; break;
case 'S': t-=x,splay(suc(rt,m-t),0),sz[rt]-=sz[ch[rt][0]],ch[rt][0]=0; break;
case 'F': printf("%d\n",query(rt,x)); break;
}
}
printf("%d\n",sum-sz[rt]);
return 0;
}