一眼看感觉有点麻烦,splay树上的权值需要全部修改,还需要一个个去删除,多看了一会后发现每个操作都挺方便的。
操作1:直接insert即可。
操作2:注意到A,S的个数和是在100以内的,所以暴力把splay树上的权值都增加即可。
操作3:暴力把splay树上的权值减少,减少以后可能会有一部分点由于权值小于minn而被删掉,对于这个删除操作,可以这样处理:找到第一个大于等于minn的节点,把这个节点移到根上去,然后删除根的左儿子即可。
操作4:这个应该大家都会了。
注意读入的时候不要作死用cin,我cin>>opt被BZOJ卡,一开始还不知道为什么超时呢。
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int n,minn,x,add,a,b,ans,sum,ncnt,root;
int ch[N][2],cnt[N],size[N],fa[N],val[N];
inline int chk(int x)
{
return ch[fa[x]][1]==x;
}
inline void pushup(int x)
{
size[x]=size[ch[x][0]]+size[ch[x][1]]+cnt[x];
}
inline void rotate(int x)
{
int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1];
ch[y][k]=w; fa[w]=y;
ch[z][chk(y)]=x; fa[x]=z;
ch[x][k^1]=y; fa[y]=x;
pushup(y); pushup(x);
}
inline void splay(int x,int goal)
{
while (fa[x]!=goal)
{
int y=fa[x],z=fa[y];
if (z!=goal)
{
if (chk(x)==chk(y)) rotate(y);
else rotate(x);
}
rotate(x);
}
if (!goal) root=x;
}
inline void insert(int x)
{
int cur=root,p=0;
while (cur && x!=val[cur])
{
p=cur;
cur=ch[cur][x>val[cur]];
}
if (cur) cnt[cur]++;
else
{
cur=++ncnt;
if (p) ch[p][x>val[p]]=cur;
ch[cur][0]=ch[cur][1]=0;
fa[cur]=p; val[cur]=x;
cnt[cur]=size[cur]=1;
}
splay(cur,0);
}
inline int find(int x)
{
int cur=root;
while (ch[cur][x>val[cur]] && x!=val[cur]) cur=ch[cur][x>val[cur]];
splay(cur,0);
}
inline int kth(int x)
{
int cur=root;
while (true)
{
if (ch[cur][1] && x<=size[ch[cur][1]]) cur=ch[cur][1];
else if (x>size[ch[cur][1]]+cnt[cur])
{
x-=size[ch[cur][1]]+cnt[cur];
cur=ch[cur][0];
}
else return cur;
}
}
inline int nxt2(int x)
{
find(x);
if (val[root]>=x) return root;
int cur=ch[root][1];
while (ch[cur][0]) cur=ch[cur][0];
return cur;
}
inline char read_char()
{
char ch=getchar();
while (ch!='I' && ch!='A' && ch!='S' && ch!='F') ch=getchar();
return ch;
}
int main(){
insert(1e8);
scanf("%d%d",&n,&minn);
for (register int i=1; i<=n; ++i)
{
char opt;
opt=read_char();
scanf("%d",&x);
if (opt=='I')
{
if (x<minn) continue;
insert(x);
}
if (opt=='A')
{
for (register int j=1; j<=ncnt; ++j) val[j]+=x;
}
if (opt=='S')
{
for (register int j=1; j<=ncnt; ++j) val[j]-=x;
int rt;
rt=nxt2(minn);
splay(rt,0);
ans+=size[ch[root][0]];
ch[root][0]=0;
pushup(root);
}
if (opt=='F')
{
if (size[root]-1<x) printf("%d\n",-1);
else
{
printf("%d\n",val[kth(x+1)]);
}
}
}
printf("%d\n",ans);
return 0;
}
对于2,3两个操作还可以通过O(1)修改来得到:
改动一下insert里的值,nxt2的值和输出的值就行。至于为什么insert(x-add),nxt2(minn-add),val[kth(x+1)]+add,自己模拟一下数据即可。
int main(){
insert(1e8);
scanf("%d%d",&n,&minn);
for (register int i=1; i<=n; ++i)
{
char opt;
opt=read_char();
scanf("%d",&x);
if (opt=='I')
{
if (x<minn) continue;
insert(x-add);
}
if (opt=='A')
{
add+=x;
}
if (opt=='S')
{
add-=x;
int rt;
rt=nxt2(minn-add);
splay(rt,0);
ans+=size[ch[root][0]];
ch[root][0]=0;
pushup(root);
}
if (opt=='F')
{
if (size[root]-1<x) printf("%d\n",-1);
else
{
printf("%d\n",val[kth(x+1)]+add);
}
}
}
printf("%d\n",ans);
return 0;
}