【题意】
如指令所示:
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本书的编号。
【题解】
伸展树
借助伸展树翻转后中序遍历不变来维护书架上书的顺序。
第一步,用二分的方法建一棵尽量平衡的树。
对于1,(如果不在第1本)把s放在树的最左孩子的左边,它就会是第一个遍历到的,即第1本;
对于2,(如果不在第n本)把s放在树的最右孩子的右边,它会是最后一个遍历到的,即第n本;
对于3,找到与s交换的那一本,硬插在它与它的孩子间。在左边位在它上一本,在右边为在它下一本;
对于4,问s的中序遍历。只需将s转到根,它左孩子的个数+1即为它的中序遍历编号;
对于5,问中序遍历第s的是谁。对于节点x,看看是在它的左子树还是右子树。
【注意与错误】
1、建树时,要注意子树不能包含自己,即build(l,mid-1),build(mid+1,r);
2、书本的实际编号 与 树上节点的编号不同,需要记录其转换关系;
3、(del函数中发现)注意数据转移过程中的顺序,不要删掉了一些后面有用的东西,导致转移中断;
4、(del函数中发现)我们的删除总是把节点旋到根来处理的,记得所有操作都要更改根的标记;
5、(find_abovenum函数中发现)中序遍历也好,求排名也好,要在左子树的数量上+1,否则会出现0;
6、任何树的操作最好放到根来做。否则相关节点的c会不能便捷地求出,因为在树的下部不好更新上部分,除非把更新的节点做一次splay旋到根,同时对整棵树进行更新。
【收获】
可以自制小数据,有针对性的试验某个指令,在合起来测试。避免在一个样例中出现多个不能保证正确性的命令,而无从下手。
【代码】
如指令所示:
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本书的编号。
【题解】
伸展树
借助伸展树翻转后中序遍历不变来维护书架上书的顺序。
第一步,用二分的方法建一棵尽量平衡的树。
对于1,(如果不在第1本)把s放在树的最左孩子的左边,它就会是第一个遍历到的,即第1本;
对于2,(如果不在第n本)把s放在树的最右孩子的右边,它会是最后一个遍历到的,即第n本;
对于3,找到与s交换的那一本,硬插在它与它的孩子间。在左边位在它上一本,在右边为在它下一本;
对于4,问s的中序遍历。只需将s转到根,它左孩子的个数+1即为它的中序遍历编号;
对于5,问中序遍历第s的是谁。对于节点x,看看是在它的左子树还是右子树。
【注意与错误】
1、建树时,要注意子树不能包含自己,即build(l,mid-1),build(mid+1,r);
2、书本的实际编号 与 树上节点的编号不同,需要记录其转换关系;
3、(del函数中发现)注意数据转移过程中的顺序,不要删掉了一些后面有用的东西,导致转移中断;
4、(del函数中发现)我们的删除总是把节点旋到根来处理的,记得所有操作都要更改根的标记;
5、(find_abovenum函数中发现)中序遍历也好,求排名也好,要在左子树的数量上+1,否则会出现0;
6、任何树的操作最好放到根来做。否则相关节点的c会不能便捷地求出,因为在树的下部不好更新上部分,除非把更新的节点做一次splay旋到根,同时对整棵树进行更新。
【收获】
可以自制小数据,有针对性的试验某个指令,在合起来测试。避免在一个样例中出现多个不能保证正确性的命令,而无从下手。
【代码】
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
int a[80010];
struct node
{
int d,c,f,son[2];
}tr[80010];int len=0,root,pos[80010];//注意树上节点的编号与实际编号的区别 pos[x]实际编号对应的树上的节点编号
void update(int x)
{
tr[x].c=tr[tr[x].son[0]].c+tr[tr[x].son[1]].c+1;
}
void clean(int x)
{
tr[x].c=tr[x].f=tr[x].son[0]=tr[x].son[1]=0;
}
int build(int l,int r)
{
if(l>r) return 0;
int mid,x;
mid=(l+r)/2;
x=++len;
tr[x].d=a[mid];
pos[a[mid]]=x;
if(l==r)
{
tr[x].son[0]=tr[x].son[1]=0;
update(x);
return x;
}
int lc,rc;
lc=tr[x].son[0]=build(l,mid-1);
rc=tr[x].son[1]=build(mid+1,r);
if(lc!=0) tr[lc].f=x;
if(rc!=0) tr[rc].f=x;
update(x);
return x;
}
void rotate(int x,int w)
{
int f=tr[x].f,ff=tr[f].f;
int r,R;
r=tr[x].son[w];R=f;
tr[R].son[1-w]=r;
if(r!=0) tr[r].f=R;
r=x;R=ff;
if(tr[ff].son[0]==f) tr[R].son[0]=r;
else tr[R].son[1]=r;
tr[r].f=R;
r=f;R=x;
tr[R].son[w]=r;
tr[r].f=R;
update(f);
update(x);
}
void splay(int x,int rt)
{
while(tr[x].f!=rt)
{
int f=tr[x].f,ff=tr[f].f;
if(tr[f].f==rt)
{
if(tr[f].son[0]==x) rotate(x,1);
else rotate(x,0);
}
if(tr[ff].son[0]==f&&tr[f].son[0]==x){rotate(f,1);rotate(x,1);}
else if(tr[ff].son[1]==f&&tr[f].son[1]==x){rotate(f,0);rotate(x,0);}
else if(tr[ff].son[0]==f&&tr[f].son[1]==x){rotate(x,0);rotate(x,1);}
else if(tr[ff].son[1]==f&&tr[f].son[0]==x){rotate(x,1);rotate(x,0);}
}
if(rt==0) root=x;
}
void del(int x)
{
splay(x,0);
if(tr[x].son[0]==0&&tr[x].son[1]==0){root=0;clean(x);}
else if(tr[x].son[0]==0&&tr[x].son[1]!=0){root=tr[x].son[1];tr[root].f=0;clean(x);}
else if(tr[x].son[0]!=0&&tr[x].son[1]==0){root=tr[x].son[0];tr[root].f=0;clean(x);}
else if(tr[x].son[0]!=0&&tr[x].son[1]!=0)
{
int p=tr[x].son[0];
while(tr[p].son[1]!=0) p=tr[p].son[1];
splay(p,x);
int r,R;
r=tr[x].son[1];R=p;
tr[R].son[1]=r;
tr[r].f=R;
root=p;tr[root].f=0;
clean(x);
update(p);
}
}
int find_head()
{
int x=root;
while(tr[x].son[0]!=0) x=tr[x].son[0];
return x;
}
int find_tail()
{
int x=root;
while(tr[x].son[1]!=0) x=tr[x].son[1];
return x;
}
int find_bookid(int k)//查询中序遍历第k的节点编号
{
int x=root;
while(1)
{
int lc=tr[x].son[0],rc=tr[x].son[1];
if(k<=tr[lc].c){x=lc;}
else if(k>tr[lc].c+1){k-=tr[lc].c+1;x=rc;}
else break;
}
return x;
}
int find_abovenum(int x)//查询x的中序遍历编号
{
splay(x,0);
return tr[tr[x].son[0]].c+1;
}
char opt[10];
int main()
{
int Q;
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
root=build(1,n);
while(Q--)
{
int s,t,x,R,r,ans;
scanf("%s",opt);
if(opt[0]=='T')
{
scanf("%d",&s);
s=pos[s];
x=find_head();
if(x==s) continue;
del(s);
splay(x,0);
R=x;r=s;
tr[R].son[0]=r;
tr[r].f=R;
update(s);
update(x);
}
else if(opt[0]=='B')
{
scanf("%d",&s);
s=pos[s];
x=find_tail();
if(x==s) continue;
del(s);
splay(x,0);
R=x;r=s;
tr[R].son[1]=r;
tr[r].f=R;
update(s);
update(x);
}
else if(opt[0]=='I')
{
scanf("%d%d",&s,&t);
s=pos[s];
if(t==-1)
{
x=find_bookid(find_abovenum(s)+t);
del(s);
splay(x,0);
R=s;r=tr[x].son[0];
tr[R].son[0]=r;
tr[r].f=R;
R=x;r=s;
tr[R].son[0]=r;
tr[r].f=R;
update(s);
update(x);
}
else if(t==1)
{
x=find_bookid(find_abovenum(s)+t);
del(s);
splay(x,0);
R=s;r=tr[x].son[1];
tr[R].son[1]=r;
tr[r].f=R;
R=x;r=s;
tr[R].son[1]=r;
tr[r].f=R;
update(s);
update(x);
}
}
else if(opt[0]=='A')
{
scanf("%d",&s);
s=pos[s];
splay(s,0);
ans=find_abovenum(s)-1;//要减去1,因为求的是上面的书的本数
printf("%d\n",ans);
}
else if(opt[0]=='Q')
{
scanf("%d",&s);
ans=tr[find_bookid(s)].d;
printf("%d\n",ans);
}
}
return 0;
}