平衡树
初始想法:
对于每个节点,新增一个变量表示当前节点的优先级,用Splay维护。
置顶/置底时先把节点取出,把优先级修改到最大/最小,再插入。
放回时把两个节点取出,交换优先级后插入。
询问的话直接做就好了。
然而打了一个下午没打出来。。。实在太烦了。。。
这时候ZZK飘了过来,看了一眼:“这不是平衡树维护序列裸题吗”
Orz
正解:
Top:把x Splay到根,然后把x的左子树合并到x的后继上。
Bottom:把x Splay到根,然后把x的右子树合并到x的前驱上。
Insert:直接交换x与其前驱/后继的信息。
Ask:把x Splay到根,答案就是它的左子树大小。
Query:直接找就好了。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 80000
using namespace std;
struct node{
int w,size,to[2],fa;
}t[N*2+5];
int n,m,rt,nd,id[N+5],num[N+5];
char s[10];
void updt(int x){
t[x].size=t[t[x].to[0]].size+t[t[x].to[1]].size+1;
id[num[t[x].to[0]]]=t[x].to[0],id[num[t[x].to[1]]]=t[x].to[1];
}
void rtt(int x,int &w){
int y=t[x].fa,z=t[y].fa,p=(t[y].to[0]!=x);
if (y==w) w=x;
else t[z].to[(t[z].to[0]!=y)]=x;
t[x].fa=z,t[y].fa=x,t[t[x].to[p^1]].fa=y;
t[y].to[p]=t[x].to[p^1],t[x].to[p^1]=y;
updt(y),updt(x);
}
void splay(int x,int &w){
while (x!=w){
int y=t[x].fa,z=t[y].fa;
if (y!=w)
if ((t[y].to[0]==x)^(t[z].to[0]==y)) rtt(x,w);
else rtt(y,w);
rtt(x,w);
}
id[num[x]]=x;
}
void nsrt(int x){
num[++nd]=x,t[nd].size=1,id[x]=nd,t[nd].to[0]=t[nd].to[1]=0;
if (nd>1) t[nd-1].to[1]=nd,t[nd].fa=nd-1,splay(nd,rt);
}
int srch(int x,int w){
int p=t[x].to[0];
if (t[p].size+1==w) return x;
if (t[p].size>=w) return srch(p,w);
return srch(t[x].to[1],w-t[p].size-1);
}
void tp(int x){
x=id[x],splay(x,rt);
if (!t[x].to[0]) return;
if (!t[x].to[1]) t[x].to[1]=t[x].to[0],t[x].to[0]=0;
else{
int p=srch(rt,t[t[x].to[0]].size+2);
t[t[rt].to[0]].fa=p,t[p].to[0]=t[rt].to[0];
t[rt].to[0]=0,splay(p,rt);
}
}
void bttm(int x){
x=id[x],splay(x,rt);
if (!t[x].to[1]) return;
if (!t[x].to[0]) t[x].to[0]=t[x].to[1],t[x].to[1]=0;
else{
int p=srch(rt,t[t[x].to[0]].size);
t[t[rt].to[1]].fa=p,t[p].to[1]=t[rt].to[1];
t[rt].to[1]=0,splay(p,rt);
}
}
void ns(int x,int w){
if (!w) return; splay(id[x],rt); w++;
int p=srch(rt,t[t[id[x]].to[0]].size+w);
int x1=num[p],x2=id[x];
swap(id[x],id[x1]);
swap(num[x2],num[p]);
}
int main(){
scanf("%d%d",&n,&m); rt=1;
for (int x,i=1;i<=n;i++)
scanf("%d",&x),nsrt(x);
for (int x,p,i=1;i<=m;i++){
scanf("%s%d",s,&x);
switch (s[0]){
case 'T': tp(x); break;
case 'B': bttm(x); break;
case 'I': scanf("%d",&p),ns(x,p); break;
case 'A': x=id[x],splay(x,rt),printf("%d\n",t[t[x].to[0]].size); break;
case 'Q': printf("%d\n",num[srch(rt,x)]); break;
}
}
return 0;
}