题目大意
给定一个长度为 nnn 的序列,你需要完成 nnn 个操作,共有 555 种操作。
操作 | 说明 |
---|---|
Top STop\ STop S | 把 SSS 移动到序列最前面 |
Bottom SBottom\ SBottom S | 把 SSS 移动到序列最后面 |
Insert S TInsert\ S\ TInsert S T | 把 SSS 向后移动 TTT 个位置,其中 T∈{1,0,−1}T\in\{1,0,-1\}T∈{1,0,−1} |
Ask SAsk\ SAsk S | 询问 SSS 是序列中的第几个元素 |
Query SQuery\ SQuery S | 询问序列中从左往右数的第 SSS 个元素 |
数据范围 1⩽n,m⩽800001 \leqslant n,m \leqslant 800001⩽n,m⩽80000
题解
需要求排名,考虑权值线段树///树状数组/Splay/Splay/Splay。
需要修改序列,考虑 SplaySplaySplay。
由于元素只有 800008000080000 个,因此对于 TopTopTop 操作和 BottomBottomBottom 操作,直接删除原位置的节点,在 SplaySplaySplay 最后///前面插入新节点。
对于 InsertInsertInsert 操作其实可以直接交换两节点的 ididid,而不需要做其他修改。
对于 QueryQueryQuery 操作,便是求排名,SplaySplaySplay 维护 sizesizesize 域即可。
重点是 AskAskAsk 操作。这里用了一个小 tricktricktrick,类似 setsetset 的 insertinsertinsert ,我们可以在 insertinsertinsert 的结尾返回插入的节点的指针,这样就可以完美解决 AskAskAsk 操作,但要注意其余修改了节点的操作都要连着一起做改动。
代码
ZZY调了半天还没调出来,我由于封装得好,一遍过……
// luogu-judger-enable-o2
#include<bits/stdc++.h>
using namespace std;
template<class T> struct node{
int size,n;
T data;
node *fa,*ch[2];
inline node(T d=T(),node *f=NULL):data(d),size(1),n(1),fa(f){
ch[0]=ch[1]=NULL;
}
inline void up(){
size=n;
if(ch[0]) size+=ch[0]->size;
if(ch[1]) size+=ch[1]->size;
}
};
#define which(p) (p->fa->ch[1]==p)
template<class T> struct Splay{
static const int maxn=80010;
int top;
node<T> *root;
node<T> *pool[maxn<<1];//内存池
inline Splay():top(0){
for(int i=0;i<maxn;i++)
pool[i]=new node<T>();
}
inline void newnode(node<T> *&p,T data,node<T> *fa){
p=pool[top++];
*p=node<T>(data,fa);
}
inline void dels(node<T> *&p){
pool[--top]=p;
p=NULL;
}
inline node<T> *&down(node<T> *&p,T x){
if(x==p->data)
return p;
return p->ch[p->data<x];
}
inline void rotate(node<T> *p){
int t=which(p);
node<T> *f=p->fa;
if(f->ch[t]=p->ch[t^1])
p->ch[t^1]->fa=f;
if(p->fa=f->fa)
p->fa->ch[which(f)]=p;
f->fa=p;p->ch[t^1]=f;
f->up();p->up();
if(p->fa==NULL)
root=p;
}
inline void splay(node<T> *p,node<T> *Fa){
for(;p->fa!=Fa;rotate(p))
if(p->fa->fa!=Fa)
rotate(which(p)==which(p->fa)?p->fa:p);
}//三行Splay不想要吗?
inline node<T>* insert(T val){
//其实插入可以删去,一开始就构造一颗完全二叉树
//但考虑到后面需要不断地Splay,对时间的影响不大
node<T> *p=root;
if(root==NULL){
newnode(root,val,NULL);
return root;
} node<T> *fa=p->fa;
while(p!=NULL){
node<T> *t=down(p,val);
if(t==p)
break;
fa=p;p=t;
} if(p==NULL){
newnode(p,val,fa);
down(fa,val)=p;
}else
++p->n;
splay(p,NULL);
return p;
}
inline node<T> *kth(int k){//求第k大
node<T> *p=root;
while(p){
int d=p->ch[0]?p->ch[0]->size:0;
if(k>=d+1&&k<=d+p->n){
splay(p,NULL);
return p;
}
if(k<d+1) p=p->ch[0];
else k-=d+p->n,p=p->ch[1];
}
return NULL;
}
inline node<T>* begin(node<T> *p){//求开头
if(!p) return NULL;
while(p->ch[0]) p=p->ch[0];
return p;
}
inline node<T>* end(node<T> *p){//求结尾
if(!p) return NULL;
while(p->ch[1]) p=p->ch[1];
return p;
}
inline node<T> *merge(node<T> *a,node<T> *b){//合并Splay
if(b==NULL) return a;
if(a==NULL) return b;
node<T> *t=end(a);
splay(t,NULL);
t->ch[1]=b;
b->fa=t;
t->up();
return t;
}
inline void del(node<T> *pos){//删除
if(pos==NULL)
return ;
if(pos->n>1){
--pos->n;
return;
} splay(pos,NULL);
pos=root;
dels(root);
root=merge(pos->ch[0],pos->ch[1]);
if(root!=NULL)
root->fa=NULL;
}
inline int rank(node<T> *pos){//求排名
splay(pos,NULL);
if(pos->ch[0])
return pos->ch[0]->size+1;
return 1;
}
inline node<T>* pre(node<T> *x){
splay(x,NULL);
return end(x->ch[0]);
}
inline node<T>* nxt(node<T> *x){
splay(x,NULL);
return begin(x->ch[1]);
}
void move_front(node<T>*&);
void move_back(node<T>*&);
};
template<class T> void Splay<T>::move_back(node<T>* &x){
T tmps=x->data;del(x);//先删除
node<T> *p=end(root);
tmps.d=p->data.d+1;//调整次序
newnode(p->ch[1],tmps,p);//加入新节点
splay(p->ch[1],NULL);
x=root;
}
template<class T> void Splay<T>::move_front(node<T>* &x){
T tmps=x->data;del(x);
node<T> *p=begin(root);
tmps.d=p->data.d-1;
newnode(p->ch[0],tmps,p);
splay(p->ch[0],NULL);
x=root;
}
template<class T> void swaps(node<T>* &a,node<T>*& b){
swap(a->data.id,b->data.id);
swap(a,b);//连着point数组一起换掉
}
struct datas{
int id,d;
datas(int ids=0,int da=0):id(ids),d(da){}
bool operator==(const datas &x)const{return d==x.d;}
bool operator<(const datas &x)const{return d<x.d;}
};
Splay<datas> t;
node<datas> *point[80010];
int n,m;
char str[110];
int main(void){
scanf("%d%d",&n,&m);
for(int i=1,x;i<=n;i++){
scanf("%d",&x);
point[x]=t.insert(datas(x,i));
}
for(int i=1,x,y;i<=m;i++){
scanf("%s%d",str,&x);
if(str[0]=='T') t.move_front(point[x]);
else if(str[0]=='B') t.move_back(point[x]);
else if(str[0]=='A') printf("%d\n",t.rank(point[x])-1);
else if(str[0]=='Q') printf("%d\n",t.kth(x)->data.id);
else{
scanf("%d",&y);
if(y==0) continue;
if(y==1) swaps(point[x],point[t.nxt(point[x])->data.id]);
else swaps(point[x],point[t.pre(point[x])->data.id]);
//连着point数组一起换掉(point[t->data.id]==t)
}
}
return 0;
}