[ZJOI2006]书架
Link
题目描述
初始时给定一个长为 \(n\) 的排列,支持以下操作:
- 将编号为 \(s\) 的元素放在序列首部
- 将编号为 \(s\) 的元素放在序列尾部
- 给定 \(t\) 表示将编号为 \(s\) 的元素往前或往后移动一位
- 查询编号为 \(s\) 的元素前面有多少个数
- 查询序列中第 \(s\) 个的元素的编号是多少
解法
显然是平衡树。
本题的重点在于如何找出编号 \(s\) 的元素在序列中的位置,如果知道了这个之后其它的东西都可以维护。
而我们其实可以多记录一个 \(fa\) 来实现。知道了 \(fa\) 之后,我们可以不断地往上跳同时累加上左子树大小。最后得到的便是比 \(s\) 位置小的数的个数+1,即这个数在序列中的位置。\(fa\) 在 \(update\) 的时候更新一下即可。
inline int getpos(int id){
int tmp=sz[lid]+1;
while(fa[id]){
if(id==s[fa[id]][1])
tmp+=sz[s[fa[id]][0]]+1;
id=fa[id];
}
return tmp;
}
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define N 100007
#define lid s[id][0]
#define rid s[id][1]
inline int read(){
int x=0,flag=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
return flag? x:-x;
}
int cnt=0,key[N],s[N][2],val[N],sz[N],pos[N],fa[N];
inline void update(int id){
sz[id]=1;
if(lid) sz[id]+=sz[lid],fa[lid]=id;
if(rid) sz[id]+=sz[rid],fa[rid]=id;
}
inline int New(int x){
key[++cnt]=rand();
sz[cnt]=1;
s[cnt][0]=s[cnt][1]=0;
fa[cnt]=0;
val[cnt]=x;
return cnt;
}
void split(int id,int k,int &x,int &y){
if(!id) x=y=0;
else{
if(sz[s[id][0]]+1<=k)
x=id,split(rid,k-sz[s[id][0]]-1,rid,y);
else
y=id,split(lid,k,x,lid);
update(id);
}
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(key[x]<key[y]){
s[x][1]=merge(s[x][1],y);
update(x);
return x;
}else{
s[y][0]=merge(x,s[y][0]);
update(y);
return y;
}
}
inline int getpos(int id){
int tmp=sz[lid]+1;
while(fa[id]){
if(id==s[fa[id]][1])
tmp+=sz[s[fa[id]][0]]+1;
id=fa[id];
}
return tmp;
}
inline int kth(int id,int k){
while(id){
if(sz[lid]>=k) id=lid;
else if(sz[lid]+1==k) return id;
else k-=sz[lid]+1,id=rid;
}
}
int n,m;
int main(){
srand(time(NULL));
n=read(),m=read();
int rt=0,x,y,z;
for(int i=1;i<=n;i++){
int x=read();
rt=merge(rt,pos[x]=New(x));
}
char op[10]={0};
while(m--){
scanf("%s",op),x=read();
if(op[0]=='T'){
x=getpos(pos[x]);
split(rt,x,y,z);
split(y,x-1,x,y);
rt=merge(merge(y,x),z);
}else if(op[0]=='B'){
x=getpos(pos[x]);
split(rt,x,y,z);
split(y,x-1,x,y);
rt=merge(merge(x,z),y);
}else if(op[0]=='I'){
int t=read();
x=getpos(pos[x]),t+=x-1;
split(rt,x,y,z);
split(y,x-1,x,y);
x=merge(x,z);
split(x,t,x,z);
rt=merge(merge(x,y),z);
}else if(op[0]=='A') printf("%d\n",getpos(pos[x])-1);
else printf("%d\n",val[kth(rt,x)]);
}
}

浙公网安备 33010602011771号