【题目描述】
小T有一个很大的书柜。这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列。她用1到n的正整数给每本书都编了号。
小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本。由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置。不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1、X或X+1本书。
当然也有特殊情况,比如在看书的时候突然电话响了或者有朋友来访。这时候粗心的小T会随手把书放在书柜里所有书的最上面或者最下面,然后转身离开。
久而久之,小T的书柜里的书的顺序就会越来越乱,找到特定的编号的书就变得越来越困难。于是她想请你帮她编写一个图书管理程序,处理她看书时的一些操作,以及回答她的两个提问:
(1)编号为X的书在书柜的什么位置;
(2)从上到下第i本书的编号是多少。
【输入格式】
第一行有两个数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本书的编号。
【输出格式】
对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。
平衡树的操作,同时存在编号与位置
考虑根据位置建立平衡树,并用pos[x]表示编号为x的书对应平衡树中的哪一个点
Top操作将左子树接到右边前驱
Bottom操作相反
Insert操作如果t=0,就不管,否则与前驱或后继交换编号,并更新编号对应点
Ask操作将pos[x]旋转至根,输出左子树size即可
Query操作find(x)输出其编号即可
#include<iostream>
#include<iomanip>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<queue>
#include<algorithm>
using namespace std;
int n,m,root,pos[80005];
char op[10];
struct Tree
{
int ch[2],fa,v;
int size;
}tree[80005];
void push_up(int k)
{
tree[k].size=tree[tree[k].ch[0]].size+tree[tree[k].ch[1]].size+1;
pos[tree[tree[k].ch[0]].v]=tree[k].ch[0],pos[tree[tree[k].ch[1]].v]=tree[k].ch[1];
}
void build(int l,int r,int fa)
{
if(l>r) return ;
int mid=(l+r)>>1;
tree[mid].size=1;
tree[mid].fa=fa;
if(mid<fa) tree[fa].ch[0]=mid;
else tree[fa].ch[1]=mid;
if(l==r) return ;
build(l,mid-1,mid);
build(mid+1,r,mid);
push_up(mid);
}
int whoson(int x)
{
return (tree[tree[x].fa].ch[0]==x?0:1);
}
void connect(int x,int fa,int son)
{
tree[x].fa=fa;
tree[fa].ch[son]=x;
}
void rotate(int x)
{
int y=tree[x].fa,mroot=tree[y].fa;
int yson=whoson(x),mrootson=whoson(y);
int B=tree[x].ch[yson^1];
connect(B,y,yson);
connect(y,x,yson^1);
connect(x,mroot,mrootson);
push_up(y);
push_up(x);
}
void Splay(int x,int tp)
{
while(tree[x].fa!=tp)
{
int y=tree[x].fa,z=tree[y].fa;
if(z!=tp)
{
if(whoson(x)^whoson(y)) rotate(x);
else rotate(y);
}
rotate(x);
}
pos[tree[x].v]=x;
if(!tp) root=x;
}
int find(int x)
{
if(x>n||x<1) return 0;
int now=root;
while(1)
{
int lsum=tree[tree[now].ch[0]].size;
if(lsum>=x) now=tree[now].ch[0];
else if(lsum+1==x) return now;
else x-=lsum+1,now=tree[now].ch[1];
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&tree[i].v),pos[tree[i].v]=i;
build(1,n,0);
root=(n+1)>>1;
for(int i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='T')
{
int x,y;
scanf("%d",&x);
x=pos[x];
Splay(x,0);
if(!tree[x].ch[0]) continue;
if(!tree[x].ch[1])
{
tree[x].ch[1]=tree[x].ch[0];
tree[x].ch[0]=0;
continue;
}
y=find(tree[tree[x].ch[0]].size+2);
Splay(y,x);
int lig=tree[x].ch[0];
tree[lig].fa=y;
tree[y].ch[0]=lig;
tree[x].ch[0]=0;
push_up(y);
}
else if(op[0]=='B')
{
int x,y;
scanf("%d",&x);
x=pos[x];
Splay(x,0);
if(!tree[x].ch[1]) continue;
if(!tree[x].ch[0])
{
tree[x].ch[0]=tree[x].ch[1];
tree[x].ch[1]=0;
continue;
}
y=find(tree[tree[x].ch[0]].size);
Splay(y,x);
int rig=tree[x].ch[1];
tree[rig].fa=y;
tree[y].ch[1]=rig;
tree[x].ch[1]=0;
push_up(y);
}
else if(op[0]=='I')
{
int x,t,y;
scanf("%d%d",&x,&t);
if(!t) continue;
x=pos[x];
Splay(x,0);
y=find(tree[tree[x].ch[0]].size+1+t);
pos[tree[x].v]=y,pos[tree[y].v]=x;
swap(tree[x].v,tree[y].v);
}
else if(op[0]=='A')
{
int x;
scanf("%d",&x);
x=pos[x];
Splay(x,0);
printf("%d\n",tree[tree[x].ch[0]].size);
}
else
{
int x;
scanf("%d",&x);
x=find(x);
printf("%d\n",tree[x].v);
}
}
}