题目链接:点击查看
题目大意:中文题
题目分析:利用Splay加一点思维还是比较容易解决的,对于所有员工加工资以及减工资的操作,别看只有100次,如果是暴力修改的话,时间复杂度能达到1e7,常数稍大点的模板可能就顶不住了,这里可以思考一下,我们在伸展树中储存的可以是每个员工的相对工资,对于老员工加工资,相对于新员工来说就是减工资了,反之同理,所以我们可以维护一个diff变量,用来记录老员工工资的变动情况,这样对于每个新加入的员工来说,其相对工资就变成了 x - diff 了,其中有个询问第 k 大的员工的工资时,从伸展树中取出数据后别忘了加上 diff 变量恢复到绝对大小,因为在伸展树中保存的是每个员工的相对大小,这样每个操作相对就比较简单了
- 新建工作档案:满足条件的直接insert就好了
- 加工资:diff += x
- 减工资:diff -= x,因为会伴随着些许员工离开公司,我们可以将现在的最低标准:( limit - diff ) 先旋转到根节点,然后其左子树中的所有节点都是小于最低工资标准的员工了,直接删除掉就可以了
- 询问第 k 大:这里有个小坑,问的是第 k 大,而不是第 k 小,因为原模板函数求得是第 k 小,所以根据下标转换一下就好了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
int ans=0;
class Splay
{
public:
int ch[N][2],f[N],size[N],cnt[N],key[N];//size:子树大小,cnt:当前节点出现次数,key:权值
int sz,root;
inline void clear(int x)
{
ch[x][0]=ch[x][1]=f[x]=size[x]=cnt[x]=key[x]=0;
}
inline bool get(int x)
{
return ch[f[x]][1]==x;
}
inline void update(int x)
{
if(x)
{
size[x]=cnt[x];
if(ch[x][0])
size[x]+=size[ch[x][0]];
if(ch[x][1])
size[x]+=size[ch[x][1]];
}
}
inline void rotate(int x)
{
int old=f[x],oldf=f[old],whichx=get(x);
ch[old][whichx]=ch[x][whichx^1];
f[ch[old][whichx]]=old;
ch[x][whichx^1]=old;
f[old]=x;
f[x]=oldf;
if(oldf)
ch[oldf][ch[oldf][1]==old]=x;
update(old);
update(x);
}
inline void splay(int x)
{
for(int fa;fa=f[x];rotate(x))
if(f[fa])
rotate((get(x)==get(fa))?fa:x);
root=x;
}
inline void insert(int x)
{
if(root==0)
{
sz++;
ch[sz][0]=ch[sz][1]=f[sz]=0;
root=sz;
size[sz]=cnt[sz]=1;
key[sz]=x;
return;
}
int now=root,fa=0;
while(1)
{
if(x==key[now])
{
cnt[now]++;
update(now);
update(fa);
splay(now);
break;
}
fa=now;
now=ch[now][key[now]<x];
if(now==0)
{
sz++;
ch[sz][0]=ch[sz][1]=0;
f[sz]=fa;
size[sz]=cnt[sz]=1;
ch[fa][key[fa]<x]=sz;
key[sz]=x;
update(fa);
splay(sz);
break;
}
}
}
inline int find(int x)//查询x的排名
{
int now=root,ans=0;
while(1)
{
if(x<key[now])
now=ch[now][0];
else
{
ans+=(ch[now][0]?size[ch[now][0]]:0);
if(x==key[now])
{
splay(now);
return ans+1;
}
ans+=cnt[now];
now=ch[now][1];
}
}
}
inline int findx(int x)//找到排名为x的点
{
int now=root;
while(1)
{
if(ch[now][0]&&x<=size[ch[now][0]])
now=ch[now][0];
else
{
int temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];
if(x<=temp)
return key[now];
x-=temp;
now=ch[now][1];
}
}
}
inline int pre()//小于某个数的最大值
{
int now=ch[root][0];
while(ch[now][1])
now=ch[now][1];
return now;
}
inline int next()//大于某个数的最小值
{
int now=ch[root][1];
while(ch[now][0])
now=ch[now][0];
return now;
}
inline void del(int x)
{
int whatever=find(x);
if(cnt[root]>1)
{
cnt[root]--;
update(root);
return;
}
if(!ch[root][0]&&!ch[root][1])
{
clear(root);
root=0;
return;
}
if(!ch[root][0])
{
int oldroot=root;
root=ch[root][1];
f[root]=0;
clear(oldroot);
return;
}
else if(!ch[root][1])
{
int oldroot=root;
root=ch[root][0];
f[root]=0;
clear(oldroot);
return;
}
int leftbig=pre(),oldroot=root;
splay(leftbig);
ch[root][1]=ch[oldroot][1];
f[ch[oldroot][1]]=root;
clear(oldroot);
update(root);
}
inline void pop(int x)
{
insert(x);
ans+=size[ch[root][0]];
size[root]-=size[ch[root][0]];
ch[root][0]=0;
del(x);
}
}tree;
int main()
{
#ifndef ONLINE_JUDGE
// freopen("input.txt","r",stdin);
// freopen("output.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
int n,m,diff=0;
scanf("%d%d",&n,&m);
while(n--)
{
char s[5];
int x;
scanf("%s%d",s,&x);
if(s[0]=='I')
{
if(x>=m)
tree.insert(x-diff);
}
else if(s[0]=='A')
{
diff+=x;
}
else if(s[0]=='S')
{
diff-=x;
tree.pop(m-diff);
}
else if(s[0]=='F')
{
int all=tree.size[tree.root];
if(x>all)
printf("%d\n",-1);
else
printf("%d\n",tree.findx(all+1-x)+diff);
}
}
printf("%d\n",ans);
return 0;
}