【BZOJ1861】【splay】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
数据范围
Source
1 /* 2 唐代李白 3 《江夏别宋之悌》 4 楚水清若空,遥将碧海通。人分千里外,兴在一杯中。 5 谷鸟吟晴日,江猿啸晚风。平生不下泪,于此泣无穷. 6 */ 7 #include <iostream> 8 #include <cstdio> 9 #include <algorithm> 10 #include <cstring> 11 #include <vector> 12 #include <utility> 13 #include <iomanip> 14 #include <string> 15 #include <cmath> 16 #include <queue> 17 #include <assert.h> 18 #include <map> 19 #include <ctime> 20 #include <cstdlib> 21 #include <stack> 22 #include <set> 23 #define LOCAL 24 const int INF = 0x7fffffff; 25 const int MAXN = 80000 + 10; 26 const int maxnode = 20000 * 2 + 200000 * 20; 27 const int MAXM = 50000 + 10; 28 const int MAX = 100000000; 29 using namespace std; 30 struct Node { 31 int siz; 32 int val;//val代表数的编号 33 Node *parent, *ch[2]; 34 35 int cmp(){ 36 if (parent->ch[0] == this) return 0; 37 else return 1; 38 } 39 }*root, mem[MAXN * 2], *book[MAXN * 2];//book为编号映射 40 int tot, n, m; 41 42 Node *NEW(int val){ 43 Node *t = new Node; 44 t->val = val; 45 t->siz = 1; 46 t->parent = t->ch[0] = t->ch[1] = NULL; 47 return t; 48 } 49 void update(Node *&t){ 50 if (t == NULL) return; 51 t->siz = 1; 52 if (t->ch[0] != NULL) t->siz += t->ch[0]->siz; 53 if (t->ch[1] != NULL) t->siz += t->ch[1]->siz; 54 return ; 55 } 56 void rotate(Node *t, int d){ 57 if (t->parent == NULL) return;//根就没必要旋转了 58 59 Node *p = t->parent; 60 p->ch[d ^ 1] = t->ch[d]; 61 if (t->ch[d] != NULL) t->ch[d]->parent = p; 62 t->parent = p->parent; 63 if (p->parent != NULL){ 64 if (p->parent->ch[1] == p) p->parent->ch[1] = t; 65 else if (p->parent->ch[0] == p) p->parent->ch[0] = t; 66 } 67 t->ch[d] = p; 68 p->parent = t; 69 update(p); 70 update(t); 71 if (root == p) root = t; 72 } 73 //将x旋转到y的子树,自己都不知道转成什么样子了... 74 void splay(Node *x, Node *y){ 75 while (x->parent != y){ 76 if (x->parent->parent == y){ 77 rotate(x, x->cmp() ^ 1); 78 }else{ 79 Node *t = x->parent; 80 //之字形 81 if (t->ch[t->cmp() ^ 1] == x) rotate(x, x->cmp()^1); 82 else rotate(t, t->cmp() ^ 1); 83 rotate(x, x->cmp() ^ 1); 84 } 85 update(x); 86 } 87 update(x); 88 } 89 //找到第k小然后splay上去 90 void find(Node *y, int k){ 91 Node *t = root; 92 while (1){ 93 if (t->siz == 1) break; 94 int c = (t->ch[0] == NULL ? 0 : t->ch[0]->siz); 95 if (c + 1 == k) break; 96 if (c >= k ) t = t->ch[0]; 97 else {t = t->ch[1], k -= c + 1;} 98 } 99 splay(t, y); 100 } 101 //插入到第pos个位置 102 void insert(Node *t, int pos, int val){ 103 find(NULL, pos + 1); 104 find(root, pos + 2); 105 106 Node *p = NEW(val); 107 root->ch[1]->ch[0] = p; 108 p->parent = root->ch[1]; 109 book[val] = p; 110 splay(p, NULL); 111 } 112 //找到元素val在t中是第几个 113 int kth(Node *t, int val){ 114 splay(book[val], NULL); 115 return root->ch[0]->siz; //不要忘了还有个INF在前面,哈哈哈 116 } 117 void erase(Node *t, int pos){ 118 find(NULL, pos); 119 find(root, pos + 2); 120 Node *p = root->ch[1]->ch[0]; 121 p->parent = NULL; 122 root->ch[1]->ch[0] = NULL; 123 delete(p); 124 } 125 126 void init(){ 127 tot = 0; 128 root = NULL; 129 root = NEW(-INF); 130 root->ch[1] = NEW(INF); 131 root->ch[1]->parent = root; 132 update(root); 133 134 //find(NULL, 2); 135 //printf("%d", root->val); 136 scanf("%d%d", &n, &m); 137 for (int i = 1; i <= n; i++){ 138 int t; 139 scanf("%d", &t); 140 insert(root, i - 1, t); 141 } 142 //printf("%d", kth(root, 10)); 143 } 144 void work(){ 145 for (int i = 1; i <= m; i++){ 146 char str[10]; 147 scanf("%s", str); 148 if (str[0] == 'T'){//无论任何时候都有n本书 149 int t; 150 scanf("%d", &t); 151 erase(root, kth(root, t)); 152 insert(root, 0, t); 153 }else if (str[0] == 'B'){ 154 int t; 155 scanf("%d", &t); 156 erase(root, kth(root, t)); 157 insert(root, n - 1, t); 158 }else if (str[0] == 'A'){ 159 int t; 160 scanf("%d", &t); 161 printf("%d\n", kth(root, t) - 1); 162 }else if (str[0] == 'Q'){ 163 int t; 164 scanf("%d", &t); 165 find(NULL, t + 1); 166 printf("%d\n", root->val); 167 }else{//修改 168 int s, t; 169 scanf("%d%d", &s, &t); 170 if (t == 0) continue;//不动 171 int tmp = kth(root, s);//记录s当前的位置 172 erase(root, tmp); 173 if (t == -1) insert(root, tmp - 2, s); 174 else insert(root, tmp, s); 175 } 176 } 177 } 178 179 int main(){ 180 181 init(); 182 work(); 183 return 0; 184 }