1. 程式人生 > >bzoj1861: [Zjoi2006]Book 書架

bzoj1861: [Zjoi2006]Book 書架

Time Limit: 4 Sec Memory Limit: 64 MB

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

題解

明明是個輕鬆愉快的模板題,結果還是寫了一個多小時哇。
還是功力不夠哇233。

#include<cstdio>
#include<iostream>
#include<algorithm> #define nd(x) (nil + (x)) using namespace std; const int N = 80000 + 10, M = 80000 + 10, inf = 0x7fffffff; struct Node{ int a, siz; Node *c[2], *f; int d() { return f->c[1] == this; } void sc(Node *x, int d) { (c[d] = x) -> f = this; } void pup() { siz = c[0]->siz + c[1]->siz + 1; } }nil[N], *root; int n, m, id[N], pos[N]; void rotate(Node *x, Node *&k){ int d = x->d(); Node *p = x->f; p->sc(x->c[!d], d); if(p == k){ x->f = k->f; k = x; } else p->f->sc(x, p->d()); x->sc(p, !d); p->pup(); x->pup(); } void splay(Node *x, Node *&k){ for(Node *y; x != k;){ y = x->f; if(y != k) (x->d() ^ y->d()) ? rotate(x, k) : rotate(y, k); rotate(x, k); } x->pup(); } Node* select(int k){ Node *p = root; while(true){ int t = p->c[0]->siz; if(t >= k) p = p->c[0]; else if(k > t + 1) p = p->c[1], k -= t + 1; else break; } return p; } void del(int k){ Node *x = select(k-1), *y = select(k+1); splay(x, root); splay(y, x->c[1]); Node *z = y->c[0]; y->c[0] = nil; z->f = nil; z->siz = 1; y->pup(); x->pup(); } inline void in(int &x); Node *build(int l, int r, Node *fa){ if(l > r) return nil; if(l == r){ Node *u = nd(l); u->a = id[l]; u->siz = 1; u->f = fa; u->c[0] = u->c[1] = nil; return u; } int mid = (l + r) >> 1; Node *u = nd(mid); u->c[0] = build(l, mid-1, u); u->c[1] = build(mid+1, r, u); u->a = id[mid]; u->f = fa; u->pup(); return u; } void outit(Node *p){ if(p == nil) return; printf("%d %d %d %d\n", p->a, p->c[0]->a, p->c[1]->a, p->siz); outit(p->c[0]); outit(p->c[1]); } void init(){ scanf("%d%d", &n, &m); for(int i = 2; i <= n + 1; i++) in(id[i]), pos[id[i]] = i; nil->c[0] = nil->c[1] = nil->f = nil; root = build(1, n+2, nil); } void move(int k, int val){ Node *z = nd(pos[k]); splay(z, root); int rk = z->c[0]->siz + 1; del(rk); Node *x, *y; if(val == inf) x = select(n), y = select(n + 1); else if(val == -inf) x = select(1), y = select(2); else x = select(rk + val - 1), y = select(rk + val); splay(x, root); splay(y, x->c[1]); z->f = y; y->c[0] = z; y->pup(); x->pup(); } void work(){ char ch[10]; int S, T; Node *u; while(m--){ scanf("%s", ch); in(S); switch(ch[0]){ case 'T': move(S, -inf); break; case 'B': move(S, inf); break; case 'I': in(T); move(S, T); break; case 'A': u = nd(pos[S]); splay(u, root); printf("%d\n", u->c[0]->siz - 1); break; case 'Q': u = select(S + 1); printf("%d\n", u->a); break; } } } int main(){ init(); work(); return 0; } inline void in(int &x){ x = 0; char c = getchar(); int f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } x *= f; }