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;
}