[BZOJ1861][ZJOI2006]书架

BZOJ
Luogu
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

sol

就是splay板子题呀(然而还是调了我将近两个小时)
操作1,2注意判本来就是Top或是Bottom的情况
操作3注意交换splay树上的两个节点的时候会涉及很多东西的变动,最好画个图仔细想一想,然后要PUSHUP!(我就是这里WA的)
操作4,5应该是最简单的,就不讲了
练细节的好题吧

code

#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 100005;
int n,m,fa[N],ls[N],rs[N],sz[N],a[N],root;
char s[N];
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
void pushup(int x){sz[x]=sz[ls[x]]+sz[rs[x]]+1;}
void R_rotate(int x)
{
	int y=fa[x],z=fa[y];
	ls[y]=rs[x];
	if (rs[x]) fa[rs[x]]=y;
	fa[x]=z;
	if (z) if (y==ls[z]) ls[z]=x;else rs[z]=x;
	rs[x]=y;fa[y]=x;
	pushup(y);
}
void L_rotate(int x)
{
	int y=fa[x],z=fa[y];
	rs[y]=ls[x];
	if (ls[x]) fa[ls[x]]=y;
	fa[x]=z;
	if (z) if (y==ls[z]) ls[z]=x;else rs[z]=x;
	ls[x]=y;fa[y]=x;
	pushup(y);
}
void splay(int x,int goal)
{
	while (fa[x]!=goal)
	{
		int y=fa[x],z=fa[y];
		if (z==goal)
			if (x==ls[y]) R_rotate(x);
			else L_rotate(x);
		else
			if (y==ls[z])
				if (x==ls[y]) R_rotate(y),R_rotate(x);
				else L_rotate(x),R_rotate(x);
			else
				if (x==ls[y]) R_rotate(x),L_rotate(x);
				else L_rotate(y),L_rotate(x);
	}
	pushup(x);
	if (!goal) root=x;
}
void Top()
{
	int x=gi();
	splay(x,0);
	if (!ls[x]) return;
	int y=ls[x];
	while (rs[y]) y=rs[y];
	splay(y,x);
	rs[y]=rs[x];if (rs[y]) fa[rs[y]]=y;
	fa[root=y]=0;pushup(y);
	while (ls[y]) y=ls[y];
	ls[y]=x;fa[x]=y;ls[x]=rs[x]=0;sz[x]=1;
	splay(x,0);
}
void Bottom()
{
	int x=gi();
	splay(x,0);
	if (!rs[x]) return;
	int y=rs[x];
	while (ls[y]) y=ls[y];
	splay(y,x);
	ls[y]=ls[x];if (ls[y]) fa[ls[y]]=y;
	fa[root=y]=0;pushup(y);
	while (rs[y]) y=rs[y];
	rs[y]=x;fa[x]=y;ls[x]=rs[x]=0;sz[x]=1;
	splay(x,0);
}
void Insert()
{
	int x=gi(),t=gi();
	splay(x,0);
	if (t==1)
	{
		int y=rs[x];
		while (ls[y]) y=ls[y];
		splay(y,x);
		swap(ls[x],ls[y]);if (ls[x]) fa[ls[x]]=x;if (ls[y]) fa[ls[y]]=y;
		rs[x]=rs[y];if (rs[x]) fa[rs[x]]=x;
		rs[y]=x;fa[x]=y;
		fa[root=y]=0;
		pushup(x);pushup(y);
	}
	if (t==-1)
	{
		int y=ls[x];
		while (rs[y]) y=rs[y];
		splay(y,x);
		swap(rs[x],rs[y]);if (rs[x]) fa[rs[x]]=x;if (rs[y]) fa[rs[y]]=y;
		ls[x]=ls[y];if (ls[x]) fa[ls[x]]=x;
		ls[y]=x;fa[x]=y;
		fa[root=y]=0;
		pushup(x);pushup(y);
	}
}
void Ask()
{
	int x=gi();
	splay(x,0);
	printf("%d\n",sz[ls[x]]);
}
void Query()
{
	int k=gi(),x=root;
	while (233)
	{
		if (k<=sz[ls[x]]) x=ls[x];
		else if (k==sz[ls[x]]+1) break;
		else k-=sz[ls[x]]+1,x=rs[x];
	}
	printf("%d\n",x);
}
int Build(int l,int r,int ff)
{
	if (l>r) return 0;
	int mid=l+r>>1;
	fa[a[mid]]=ff;
	ls[a[mid]]=Build(l,mid-1,a[mid]);
	rs[a[mid]]=Build(mid+1,r,a[mid]);
	pushup(a[mid]);
	return a[mid];
}
int main()
{
	n=gi();m=gi();
	for (int i=1;i<=n;i++)
		a[i]=gi();
	root=Build(1,n,0);
	while (m--)
	{
		scanf("%s",s);
		if (s[0]=='T') Top();
		if (s[0]=='B') Bottom();
		if (s[0]=='I') Insert();
		if (s[0]=='A') Ask();
		if (s[0]=='Q') Query();
	}
	return 0;
}

posted @ 2018-01-02 09:51  租酥雨  阅读(190)  评论(0编辑  收藏  举报