Description
小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。 当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。 久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:(1)编号为X的书在书柜的什么位置;(2)从上到下第i本书的编号是多少。
Input
第一行有两个数n,m,分别表示书的个数以及命令的条数;第二行为n个正整数:第i个数表示初始时从上至下第i个位置放置的书的编号;第三行到m+2行,每行一条命令。命令有5种形式: 1. Top S——表示把编号为S的书房在最上面。 2. Bottom S——表示把编号为S的书房在最下面。 3. Insert S T——T∈{-1,0,1},若编号为S的书上面有X本书,则这条命令表示把这本书放回去后它的上面有X+T本书; 4. Ask S——询问编号为S的书的上面目前有多少本书。 5. Query S——询问从上面数起的第S本书的编号。
Output
对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。
Sample Input
10 10
1 3 2 7 5 8 10 4 9 6
Query 3
Top 5
Ask 6
Bottom 3
Ask 3
Top 6
Insert 4 -1
Query 5
Query 2
Ask 2
Sample Output
2
9
9
7
5
3
HINT
数据范围
100%的数据,n,m < = 80000
Source
思维难度:NOIP+
代码难度:省选
算法:平衡树
#include<cstdio>
#include<iostream>
using namespace std;
const int Maxn=160005;
const int inf=160005;
int ch[Maxn][2],fa[Maxn],val[Maxn],sum[Maxn],root,maxn,minn,n,m;
inline void pushup(int rt){
sum[rt]=sum[ch[rt][0]]+sum[ch[rt][1]]+1;
}
inline void rotate(int x){
int y=fa[x],z=fa[y],k=ch[y][1]==x,w=ch[x][!k];
if(z)ch[z][ch[z][1]==y]=x;ch[y][k]=w;ch[x][!k]=y;
if(w)fa[w]=y;fa[y]=x;fa[x]=z;
pushup(x);pushup(y);
}
inline void splay(int x){
int y,z;
while(fa[x]){
y=fa[x],z=fa[y];
if(z)rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y);
rotate(x);
}
root=x;
}
inline int ranking(int x){
splay(x);
return sum[ch[x][0]];
}
inline int kth(int k){
int x=root;
while(1){
if(sum[ch[x][0]]+1==k)return x;
if(sum[ch[x][0]]+1>k)x=ch[x][0];
else{
k-=sum[ch[x][0]]+1;
x=ch[x][1];
}
}
}
inline int lower(int key){//这里是值!!不是编号!!
int x=root,ans=-inf,v;
while(x){
if(key<=val[x]){
x=ch[x][0];
}
else{
if(ans<val[x])ans=val[x],v=x;
x=ch[x][1];
}
}
return v;
}
inline int uper(int key){
int x=root,ans=inf,v;
while(x){
if(key<val[x]){
if(ans>val[x])ans=val[x],v=x;
x=ch[x][0];
}
else{
x=ch[x][1];
}
}
return v;
}
inline void delet(int x){//x 是编号!
while(ch[x][0]||ch[x][1]){
if(ch[x][0])rotate(ch[x][0]);
else rotate(ch[x][1]);
}
ch[fa[x]][ch[fa[x]][1]==x]=0;
sum[x]=0;
while(fa[x]){
x=fa[x];
pushup(x);
}
splay(x);
}
inline void build(int key,int id,int rt){
if(key<val[rt]){
if(!ch[rt][0]){
ch[rt][0]=id;
fa[id]=rt;
pushup(rt);
return;
}
build(key,id,ch[rt][0]);
}
else{
if(!ch[rt][1]){
ch[rt][1]=id;
fa[id]=rt;
pushup(rt);
return;
}
build(key,id,ch[rt][1]);
}
pushup(rt);
}
inline void insert(int key,int id){
sum[id]=1;val[id]=key;
if(root==0){
root=id;
return;
}
build(key,id,root);
splay(id);
}
inline int read(){
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
int main(){
char s[15];int u,v,idx,x1,x2,cnt=0;
n=read();m=read();maxn=n;minn=1;
for(int i=1;i<=n;i++){
u=read();
insert(i,u);
}
for(int i=1;i<=m;i++){
cin>>s;u=read();
if(s[0]=='T'){
delet(u);
insert(minn=minn-1,u);
}
if(s[0]=='B'){
delet(u);
insert(maxn=maxn+1,u);
}
if(s[0]=='I'){
v=read();
if(v==-1){
idx=lower(val[u]);
x1=val[idx],x2=val[u];
delet(u);delet(idx);insert(x1,u);insert(x2,idx);
}
if(v==1){
idx=uper(val[u]);
x1=val[idx],x2=val[u];
delet(u);delet(idx);insert(x1,u);insert(x2,idx);
}
}
if(s[0]=='A'){
printf("%d\n",ranking(u));
}
if(s[0]=='Q'){
printf("%d\n",kth(u));
}
}
return 0;
}