[BZOJ1861][Zjoi2006]Book 书架
[BZOJ1861][Zjoi2006]Book 书架
试题描述
小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本书的编号。
输出
输入示例
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
输出示例
2 9 9 7 5 3
数据规模及约定
100%的数据,n,m < = 80000
题解
让每个节点的编号与它在伸展树中的编号一致,查找排名时利用子树大小,查询某节点排名时把它伸展到根就好了。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <algorithm> using namespace std; int read() { int x = 0, f = 1; char c = getchar(); while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); } return x * f; } #define maxn 80010 struct Node { int siz; Node() {} } ns[maxn]; int ToT, fa[maxn], ch[2][maxn], id[maxn]; void maintain(int o) { ns[o].siz = 1; for(int i = 0; i < 2; i++) if(ch[i][o]) ns[o].siz += ns[ch[i][o]].siz; return ; } void build(int& o, int l, int r) { if(l > r) return ; int mid = l + r >> 1; o = id[mid]; build(ch[0][o], l, mid - 1); build(ch[1][o], mid + 1, r); if(ch[0][o]) fa[ch[0][o]] = o; if(ch[1][o]) fa[ch[1][o]] = o; return maintain(o); } void rotate(int u) { int y = fa[u], z = fa[y], l = 0, r = 1; if(z) ch[ch[1][z]==y][z] = u; if(ch[1][y] == u) swap(l, r); fa[u] = z; fa[y] = u; fa[ch[r][u]] = y; ch[l][y] = ch[r][u]; ch[r][u] = y; maintain(y); maintain(u); return ; } void splay(int u) { while(fa[u]) { int y = fa[u], z = fa[y]; if(z) { if(ch[0][y] == u ^ ch[0][z] == y) rotate(u); else rotate(y); } rotate(u); } return ; } int splitl(int u) { splay(u); int tmp = ch[0][u]; fa[tmp] = ch[0][u] = 0; maintain(u); return tmp; } int splitr(int u) { splay(u); int tmp = ch[1][u]; fa[tmp] = ch[1][u] = 0; maintain(u); return tmp; } int merge(int a, int b) { if(!a) return maintain(b), b; if(!b) return maintain(a), a; while(ch[1][a]) a = ch[1][a]; splay(a); ch[1][a] = b; fa[b] = a; return maintain(a), a; } int getrt() { int u = 1; while(fa[u]) u = fa[u]; return u; } int Find(int o, int k) { if(!o) return 0; int ls = ch[0][o] ? ns[ch[0][o]].siz : 0; if(k == ls + 1) return o; if(k > ls + 1) return Find(ch[1][o], k - ls - 1); return Find(ch[0][o], k); } int main() { int n = read(), q = read(); for(int i = 1; i <= n; i++) id[i] = read(); int tmp = 0; build(tmp, 1, n); int tq = q; while(q--) { char cmd[10]; scanf("%s", cmd); if(cmd[0] == 'T') { int mrt = read(), lrt = splitl(mrt), rrt = splitr(mrt); lrt = merge(lrt, rrt); merge(mrt, lrt); } if(cmd[0] == 'B') { int mrt = read(), lrt = splitl(mrt), rrt = splitr(mrt); lrt = merge(lrt, rrt); merge(lrt, mrt); } if(cmd[0] == 'I') { int mrt = read(), t = read(), rk, lrt, rrt; if(!t) continue; splay(mrt); rk = (ch[0][mrt] ? ns[ch[0][mrt]].siz : 0) + 1 + t; if(rk < 1 || rk > n) continue; rk = Find(getrt(), rk); if(t < 0) { lrt = splitl(rk); splitl(mrt); rrt = splitr(mrt); lrt = merge(lrt, mrt); lrt = merge(lrt, rk); merge(lrt, rrt); } else { lrt = splitl(mrt); splitl(rk); rrt = splitr(rk); lrt = merge(lrt, rk); lrt = merge(lrt, mrt); merge(lrt, rrt); } } if(cmd[0] == 'A') { int u = read(); splay(u); printf("%d\n", ch[0][u] ? ns[ch[0][u]].siz : 0); } if(cmd[0] == 'Q') printf("%d\n", Find(getrt(), read())); } return 0; }