看到这一题我们就可以想到Splay。
具体来说,这一题要求维护下列四个操作:
将序列中的一个数与它的前一个数/后一个数交换。
将序列中的一个数移到序列头/序列尾。
如果单单如此的话那这一题就太简单了。对于一二操作只需要直接和前驱、后继调换,对于三四操作只需要将左/右子树移动到右/左子树的最左/右节点的左/右孩子。
但事实上并非这样。这一题对序列中数的操作并非是直接给出的,而是对序列中的每一个点编了号,然后每一次访问这个编号。
但仔细思考就会发现,考虑到对序列的操作只会更换位置,
故而,对于这种操作,我们定义一个数组名为loc,储存的是,编号为\(loc_i\)的数在数列中的标号。
要十分注意编号和逆编号的对应关系。以及交换之后对它们原来的关系的影响。
#include<iostream>
#include<cstdio>
#define MID ((L+R)>>1)
int loc[80005],aloc[80005];
class Splay{
private:
class Node{
public:
int fa;
int sn[2];
int sz;
inline void prnt(){
printf("(%d,%d,%d)\n",fa,sn[0],sn[1]);
}
inline Node(int FA=0,int LS=0,int RS=0,int SZ=0){
fa=FA,sn[0]=LS,sn[1]=RS,sz=SZ;
}
};
Node tr[80005];
int rt;
inline void updt(int X){
tr[X].sz=tr[tr[X].sn[0]].sz+tr[tr[X].sn[1]].sz+1;
}
inline int fndD(int X){
return tr[tr[X].fa].sn[1]==X;
}
inline void splayOne(int X){
int D=fndD(X),D2=fndD(tr[X].fa);
tr[tr[X].sn[D^1]].fa=tr[X].fa,tr[tr[X].fa].sn[D]=tr[X].sn[D^1];
tr[X].sn[D^1]=tr[X].fa,tr[X].fa=tr[tr[X].fa].fa;
tr[tr[X].fa].sn[D2]=X,tr[tr[X].sn[D^1]].fa=X;
updt(tr[X].sn[D^1]),updt(X);
}
inline void splayTwo(int X){
int D=fndD(X),D2=fndD(tr[X].fa);
tr[X].fa?(tr[tr[X].fa].fa?(D==D2?(splayOne(tr[X].fa),splayOne(X),0):(splayOne(X),splayOne(X),0)):(splayOne(X),0)):0;
}
inline void splayRnw(int X){
while(tr[X].fa){
splayTwo(X);
}
rt=X;
}
inline int fnd(int K){
int P=rt,FP=0;
while(P){
FP=P;
if(tr[tr[P].sn[0]].sz+1<K){
K-=(tr[tr[P].sn[0]].sz+1);
P=tr[P].sn[1];
}else if(tr[tr[P].sn[0]].sz<K){
return P;
}else{
P=tr[P].sn[0];
}
}
return FP;
}
inline int fndMn(int X){
int P=X,FP=tr[X].fa;
while(P){
FP=P;
P=tr[P].sn[0];
}
return FP;
}
inline int fndMx(int X){
int P=X,FP=tr[X].fa;
while(P){
FP=P;
P=tr[P].sn[1];
}
return FP;
}
inline int build(int L,int R,int FA){
if(L>R){
return 0;
}
tr[MID].fa=FA,tr[MID].sz=1;
tr[MID].sn[0]=build(L,MID-1,MID);
tr[MID].sn[1]=build(MID+1,R,MID);
updt(MID);
return MID;
}
inline void prnt(int X){
if(!X){
return;
}
prnt(tr[X].sn[0]);
printf("%d ",X);
prnt(tr[X].sn[1]);
}
public:
inline void INIT(int N){
build(1,N,0);
rt=(1+N)>>1;
}
inline void SWAP(int X,int D){
splayRnw(X);
int P=D?fndMn(tr[X].sn[1]):fndMx(tr[X].sn[0]);
int X_2=aloc[X],P_2=aloc[P];
std::swap(loc[X_2],loc[P_2]);
std::swap(aloc[X],aloc[P]);
splayRnw(X);
}
inline void LST(int X){
splayRnw(X);
int P=fndMn(tr[X].sn[1]);
tr[tr[X].sn[0]].fa=P,tr[P].sn[0]=tr[X].sn[0],tr[X].sn[0]=0;
splayRnw(tr[P].sn[0]);
}
inline void RST(int X){
splayRnw(X);
int P=fndMx(tr[X].sn[0]);
tr[tr[X].sn[1]].fa=P,tr[P].sn[1]=tr[X].sn[1],tr[X].sn[1]=0;
splayRnw(tr[P].sn[1]);
}
inline int RNK(int X){
splayRnw(X);
return tr[tr[X].sn[0]].sz;
}
inline int ARNK(int X){
int P=fnd(X);
splayRnw(P);
return P;
}
inline void PRINT(){
printf("%d ->",rt);
prnt(rt);
puts("");
}
};
int n,m;
Splay T;
void init(){
scanf("%d%d",&n,&m);
T.INIT(n);
int x,t;
for(int i=1;i<=n;++i){
scanf("%d",&x);
loc[x]=i,aloc[i]=x;
}
char op[10];
for(int i=1;i<=m;++i){
std::cin>>op;
scanf("%d",&x);
switch(op[0]){
case 'T':{
T.LST(loc[x]);
break;
}
case 'B':{
T.RST(loc[x]);
break;
}
case 'I':{
scanf("%d",&t);
t==0?0:(T.SWAP(loc[x],t==-1?0:1),0);
break;
}
case 'A':{
printf("%d\n",T.RNK(loc[x]));
break;
}
case 'Q':{
printf("%d\n",aloc[T.ARNK(x)]);
break;
}
}
}
}
int main(){
init();
return 0;
}