洛谷 P2596 [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的书的上面目前有多少本书。

扫描二维码关注公众号,回复: 5455425 查看本文章

5. Query S——询问从上面数起的第S本书的编号。

输出格式:

对于每一条Ask或Query语句你应该输出一行,一个数,代表询问的答案。

输入输出样例

输入样例#1: 

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

输出样例#1: 

2
9
9
7
5
3

说明

100%的数据,n,m <= 80000

解题思路

博主是用splay树写的。建树的时候,把x存在数组下标为x的地方(可以直接获取存了元素x的数组下标),然后接在上一个输入元素的右子树,然后把该元素旋转到根。对于找前驱和后继的方法,假设要找x的后继,先把x旋转到根,然后从x的右孩子开始,一直往左子树找,就是比x大的最小值,前驱同理。下面是各命令对应的方法。

1. Top S——表示把编号为S的书放在最上面。

先把s旋转到根,然后找到s的后继e,把s的左子树接在e的左子树上,然后把e旋转到根。如果s是第x本书,那后继e就是第x+1本,e的左子树必为空,s的左子树是前x-1本书,把s的左子树接到e的左子树上,就相当于把前x-1本书放在第x+1本书上面,把第x本书放在最上面。

2. Bottom S——表示把编号为S的书放在最下面。

先把s旋转到根,然后找到s的前驱e,把s的右子树接在e的右子树上。然后把e旋转到根。和1操作同理。

3. Insert S T——T∈{-1,0,1},若编号为S的书上面有X本书,则这条命令表示把这本书放回去后它的上面有X+T本书;

找到s的前驱(或后继,由t决定)e,交换s和e的位置信息,注意要修改其父子的对应信息,以及s是e的父亲的情况。修改根为e。

4. Ask S——询问编号为S的书的上面目前有多少本书。

将s旋转到根,此时s的左子树的sum值就是s上面的书的本数。

5. Query S——询问从上面数起的第S本书的编号。

从根开始查询,和常规的操作一样。

代码如下

#include <iostream>
#include <cstdio>
#define maxn 80005
#define INF 100000
using namespace std;
int root;
int point;
struct node{
	int fa, ch[2];
	int v;
	int recy, sum;
}tree[maxn];
void crepoint(int k, int v, int fa)
{
	tree[k].fa = fa;
	tree[k].ch[0] = tree[k].ch[1] = 0;
	tree[k].v = v;
	tree[k].recy = 1;
	tree[k].sum = 1;
}

int get(int x)
{
	return tree[tree[x].fa].ch[1] == x;
}
void connect(int son, int fa, int i)
{
	tree[son].fa = fa;
	tree[fa].ch[i] = son;
}
void update(int x)
{
	tree[x].sum = tree[tree[x].ch[0]].sum + tree[tree[x].ch[1]].sum + tree[x].recy;
}
void rotate(int x)
{
	int y = tree[x].fa;
	int z = tree[y].fa;
	int u = get(x);
	int v = get(y);
	connect(tree[x].ch[u^1], y, u);
	connect(x, z, v);
	connect(y, x, u^1);
	update(y);
	update(x);
}
void splay(int now, int to)
{
	if(to == root)
		root = now;  
	to = tree[to].fa;
	while(tree[now].fa != to){
		int up = tree[now].fa;
		if(tree[up].fa == to)
			rotate(now);
		else if(get(now) == get(up)){
			rotate(now);
			rotate(now);
		}
		else{
			rotate(up);
			rotate(now);
		}
	}
}  
void build(int v, int fa) //
{
	crepoint(v, v, fa);
	point ++;
	if(point > 1){
		tree[fa].ch[1] = v;
		splay(v, root);
	}
	else 
		root = v;	
}
int upper(int x)
{
	int now = tree[x].ch[1];
	while(tree[now].ch[0] != 0){
		now = tree[now].ch[0];
	}
		
	return now;
}
int lower(int x)
{
	int now = tree[x].ch[0];
	while(tree[now].ch[1] != 0)
		now = tree[now].ch[1];
	return now;
}
void top(int x)
{
	splay(x, root);
	if(!tree[x].ch[0])
		return;
	else if(!tree[x].ch[1]){
		tree[x].ch[1] = tree[x].ch[0];
		tree[x].ch[0] = 0;
	}
	else {
		int t = upper(x);
		connect(tree[x].ch[0], t, 0);
		tree[x].ch[0] = 0;
		splay(t, root);  //延展的时候自动更新了 
	}
}
void bottom(int x)
{
	splay(x, root);
	if(!tree[x].ch[1])
		return;
	else if(!tree[x].ch[0]){
		tree[x].ch[0] = tree[x].ch[1];
		tree[x].ch[1] = 0;
	}
	else {
		int t = lower(x);
		connect(tree[x].ch[1], t, 1);
		tree[x].ch[1] = 0;
		splay(t, root);
	}
}
void swp(int& a, int& b)
{
 	int temp = a;
	a = b;
	b = temp; 
}
void ask(int x)
{
	splay(x, root);
	cout << tree[tree[x].ch[0]].sum << endl;
}
void query(int k)
{
	int now = root;
	while(true){
		int left = tree[now].ch[0];
		if(k <= tree[left].sum)
			now = left;
		else if(k > tree[left].sum + tree[now].recy){
			k -= tree[left].sum + tree[now].recy;
			now = tree[now].ch[1];
		}
		else{
			cout << now << endl;
			splay(now, root);
			return;
		} 		
	}
}
void insert(int x, int y) 
{
	int t;
	splay(x, root);
	if(y == 0)
		return;
	else if(y == 1)
		t = upper(x);
	else 
		t = lower(x);
	swp(tree[x].sum, tree[t].sum);
	int u = get(t);
	if(tree[t].fa == x){
		int temp = tree[x].ch[u^1];
		tree[x].fa = t;
		tree[t].fa = 0;
		tree[x].ch[0] = tree[t].ch[0];
		tree[x].ch[1] = tree[t].ch[1];
		tree[t].ch[u] = x;
		tree[t].ch[u^1] = temp;
	}
	else {
		swp(tree[x].fa, tree[t].fa);
		swp(tree[x].ch[0], tree[t].ch[0]);
		swp(tree[x].ch[1], tree[t].ch[1]);
	}
	tree[tree[x].fa].ch[u] = x;
	tree[tree[x].ch[0]].fa = tree[tree[x].ch[1]].fa = x;
	tree[tree[t].ch[0]].fa = tree[tree[t].ch[1]].fa = t;
	root = t;
}
int main()
{
	int n, m;
	cin >> n >> m;
	int last = 0;
	for(int i = 1; i <= n; i ++){
		int num;
		scanf("%d", &num);
		build(num, last);
		last = num;
	}
	for(int i = 0; i < m; i ++){
		char ch[10];
		int s;
		scanf("%s%d", ch, &s);
		if(ch[0] == 'T')
			top(s);
		else if(ch[0] == 'B')
			bottom(s);
		else if(ch[0] == 'I'){
			int t;
			cin >> t;
			insert(s, t);
		}
		else if(ch[0] == 'A')
			ask(s);
		else 
			query(s);
	}
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/whisperlzw/article/details/87894876
今日推荐