题目描述
小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语句你应该输出一行,一个数,代表询问的答案。
输入输出样例
输入样例#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;
}