题目大意
给定一个长度为 n n n 的序列,你需要完成 n n n 个操作,共有 5 5 5 种操作。
操作 | 说明 |
---|---|
T o p S Top\ S Top S | 把 S S S 移动到序列最前面 |
B o t t o m S Bottom\ S Bottom S | 把 S S S 移动到序列最后面 |
I n s e r t S T Insert\ S\ T Insert S T | 把 S S S 向后移动 T T T 个位置,其中 T ∈ { 1 , 0 , − 1 } T\in\{1,0,-1\} T∈{1,0,−1} |
A s k S Ask\ S Ask S | 询问 S S S 是序列中的第几个元素 |
Q u e r y S Query\ S Query S | 询问序列中从左往右数的第 S S S 个元素 |
数据范围 1 ⩽ n , m ⩽ 80000 1 \leqslant n,m \leqslant 80000 1⩽n,m⩽80000
题解
需要求排名,考虑权值线段树
/
/
/树状数组
/
S
p
l
a
y
/Splay
/Splay。
需要修改序列,考虑
S
p
l
a
y
Splay
Splay。
由于元素只有
80000
80000
80000 个,因此对于
T
o
p
Top
Top 操作和
B
o
t
t
o
m
Bottom
Bottom 操作,直接删除原位置的节点,在
S
p
l
a
y
Splay
Splay 最后
/
/
/前面插入新节点。
对于
I
n
s
e
r
t
Insert
Insert 操作其实可以直接交换两节点的
i
d
id
id,而不需要做其他修改。
对于
Q
u
e
r
y
Query
Query 操作,便是求排名,
S
p
l
a
y
Splay
Splay 维护
s
i
z
e
size
size 域即可。
重点是
A
s
k
Ask
Ask 操作。这里用了一个小
t
r
i
c
k
trick
trick,类似
s
e
t
set
set 的
i
n
s
e
r
t
insert
insert ,我们可以在
i
n
s
e
r
t
insert
insert 的结尾返回插入的节点的指针,这样就可以完美解决
A
s
k
Ask
Ask 操作,但要注意其余修改了节点的操作都要连着一起做改动。
代码
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;
}