【Splay】【ZJOI2006】书架

【题目描述】

小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
#include
#include
#include
#include
#include
#include
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(midn||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);
		}
	}
}

 

你可能感兴趣的:(数据结构,平衡树)