BZOJ1861: [Zjoi2006]Book 书架

BZOJ1861: [Zjoi2006]Book 书架

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

题解Here!
Splay比较好做,那就一发 Splay 吧。
1. Top 和 Bottom 实质上就是把序列中的一个数放到第一个和最后一个。
具体实现可以把要操作的节点提到根节点,然后把左子树合并到右子树上或把右子树合并到左子树上。

2. Insert操作就是把要操作的节点和前驱后继交换位置,即:把两个点的特征值即编号进行交换。

3. Ask操作询问序列中在此节点前面的数有多少个,提到根节点输出左儿子size就可以了。

4. Query操作就是一个简单的查询序列中第s个数的编号,相当于查询第k大,kth即可。

由于我们需要定位编号为s的节点在树中的位置,所以我使用了 id 数组记录并维护。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 80010
using namespace std;
int n,m,root=1,c=1,id[MAXN];
struct node{
	int son[2];
	int f,v,s;
}a[MAXN];
inline int read(){
	int date=0,w=1;char c=0;
	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
	return date*w;
}
inline void clean(int rt){
	a[rt].son[0]=a[rt].son[1]=a[rt].f=a[rt].v=a[rt].s=0;
}
inline void pushup(int rt){
	if(!rt)return;
	a[rt].s=a[a[rt].son[0]].s+a[a[rt].son[1]].s+1;
	id[a[a[rt].son[0]].v]=a[rt].son[0];id[a[a[rt].son[1]].v]=a[rt].son[1];
}
inline void turn(int rt,int k){
	int x=a[rt].f,y=a[x].f;
	a[x].son[k^1]=a[rt].son[k];
	if(a[rt].son[k])a[a[rt].son[k]].f=x;
	a[rt].f=y;
	if(y)a[y].son[a[y].son[1]==x]=rt;
	a[x].f=rt;
	a[rt].son[k]=x;
	pushup(x);pushup(rt);
}
void splay(int rt,int ancestry){
	while(a[rt].f!=ancestry){
		int x=a[rt].f,y=a[x].f;
		if(y==ancestry)turn(rt,a[x].son[0]==rt);
		else{
			int k=a[y].son[0]==x?1:0;
			if(a[x].son[k]==rt){turn(rt,k^1);turn(rt,k);}
			else{turn(x,k);turn(rt,k);}
		}
	}
	if(ancestry==0)root=rt;
}
int kth(int rt,int x){
	int y=a[rt].son[0];
	if(a[y].s+1==x)return rt;
	else if(x<=a[y].s)return kth(y,x);
	else return kth(a[rt].son[1],x-a[y].s-1);
}
inline void newnode(int x){
	int rt=c++;
	a[rt].son[0]=a[rt].son[1]=0;
	a[rt].v=x;a[rt].s=1;id[x]=rt;
	if(rt==1)return;
	a[rt-1].son[1]=rt;a[rt].f=rt-1;
	splay(rt,0);
}
inline void top(int x){
	int rt=id[x];
	splay(rt,0);
	if(!a[rt].son[0])return;
	if(!a[rt].son[1]){
		a[rt].son[1]=a[rt].son[0];
		a[rt].son[0]=0;
	}
	else{
		int y=kth(root,a[a[rt].son[0]].s+2);
		a[a[root].son[0]].f=y;
		a[y].son[0]=a[root].son[0];
		a[root].son[0]=0;
		splay(y,0);
	}
}
inline void bottom(int x){
	int rt=id[x];
	splay(rt,0);
	if(!a[rt].son[1])return;
	if(!a[rt].son[0]){
		a[rt].son[0]=a[rt].son[1];
		a[rt].son[1]=0;
	}
	else{
		int y=kth(root,a[a[rt].son[0]].s);
		a[a[root].son[1]].f=y;
		a[y].son[1]=a[root].son[1];
		a[root].son[1]=0;
		splay(y,0);
	}
}
inline void insert(int x,int y){
	if(!y)return;
	splay(id[x],0);
	int p,q,k=kth(root,a[a[id[x]].son[0]].s+y+1);
	p=a[k].v;q=id[x];
	swap(id[x],id[p]);swap(a[q].v,a[k].v);
}
inline int ask(int x){
	x=id[x];
	splay(x,0);
	return a[a[x].son[0]].s;
}
int main(){
	char ch[10];
	int x,y;
	n=read();m=read();
	for(int i=1;i<=n;i++){
		x=read();
		newnode(x);
	}
	while(m--){
		scanf("%s",ch);x=read();
		switch(ch[0]){
			case 'T':top(x);break;
			case 'B':bottom(x);break;
			case 'I':y=read();insert(x,y);break;
			case 'A':printf("%d\n",ask(x));break;
			case 'Q':printf("%d\n",a[kth(root,x)].v);break;
		}
	}
	return 0;
}

 

posted @ 2018-05-01 22:28  符拉迪沃斯托克  阅读(163)  评论(0编辑  收藏  举报
Live2D