1. 程式人生 > >bzoj1861: [Zjoi2006]Book 書架(平衡樹)

bzoj1861: [Zjoi2006]Book 書架(平衡樹)

一個數 () == wap pre 吸引力 root 圖書管理 模板

原題鏈接

題目描述:小T有一個很大的書櫃。這個書櫃的構造有些獨特,即書櫃裏的書是從上至下堆放成一列。她用1到的正整數給每本書都編了號。 小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語句你應該輸出一行,一個數,代表詢問的答案。

輸入樣例
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

解析:算是平衡樹中比較經典的題了,用splay和treap都可以解決。這裏給出treap的做法。
???將每本書的位置作為權值插入treap中,記錄val[x]為編號為x的書的位置。
???相比與treap的模板,要多對每一個節點記錄一個ind,表示該點所表述的書的編號。
???那麽對於Top操作,便是將原先書x的節點刪除,再插入該節點(節點的權值要是所有數中最小的)。

???對於Bottom操作,就是將原先書x的節點刪除,再插入該節點(節點的權值要是所有數中最大的)。
???對於Insert操作。若t是0,就直接continue;否則就將兩個點都刪除,再將兩個點的信息交換後插入。
???對於Ask操作,就是輸出val[x]的排名再-1。
???對於Query操作,就是輸出排名為x的數的ind值。

代碼如下:

#include<cstdio>
#include<algorithm>
using namespace std;

const int maxn = 80005;
int n, m, root, val[maxn];
int size[maxn << 1], lson[maxn << 1], rson[maxn << 1], c[maxn << 1], cnt, a[maxn << 1], pri[maxn << 1], ind[maxn << 1]; //數組要開兩倍! 
char s[10];

int read(void) {
    char c; while (c = getchar(), (c < '0' || c > '9') && c != '-'); int x = 0, y = 1;
    if (c == '-') y = -1; else x = c - '0';
    while (c = getchar(), c >= '0' && c <= '9') x = x * 10 + c - '0'; return x * y; 
}

int rand() { 
    static int seed = 2333;
    return seed = (int)((((seed ^ 998244353) + 19260817ll) * 19890604ll) % 1000000007);
}

void up(int k) {
    size[k] = size[lson[k]] + size[rson[k]] + c[k];
}

void zig(int &k) {
    int v = rson[k]; rson[k] = lson[v]; lson[v] = k;
    size[v] = size[k]; up(k); k = v;
}

void zag(int &k) {
    int v = lson[k]; lson[k] = rson[v]; rson[v] = k;
    size[v] = size[k]; up(k); k = v;
}

void insert(int &k, int x, int id) { 
    if (k == 0) { 
      k = ++ cnt;  
      size[k] = c[k] = 1; a[k] = x; pri[k] = rand(); ind[k] = id;
      return;
    }
    size[k] ++;
    if (a[k] == x) c[k] ++;
    else if (x > a[k]) {
      insert(rson[k], x, id);
      if (pri[rson[k]] < pri[k]) zig(k);
    }
    else {
      insert(lson[k], x, id);
      if (pri[lson[k]] < pri[k]) zag(k);
    }
}

void del(int &k, int x) { 
    if (k == 0) return; 
    if (a[k] == x) {
      if (c[k] > 1) c[k] --, size[k] --;
      else {
        if (!lson[k] || !rson[k]) k = lson[k] + rson[k];
        else if (pri[lson[k]] < pri[rson[k]]) zag(k), del(k, x);
        else zig(k), del(k, x);
      }
    }
    else if (x > a[k]) size[k] --, del(rson[k], x);
    else size[k] --, del(lson[k], x);
}

int query_rank(int k, int x) { 
    if (k == 0) return 2e9;
    if (a[k] == x) return size[lson[k]] + 1;
    if (x > a[k]) return size[lson[k]] + c[k] + query_rank(rson[k], x);
    else return query_rank(lson[k], x);
}

int query_num(int k, int x) { 
    if (k == 0) return 2e9;
    if (x <= size[lson[k]]) return query_num(lson[k], x);
    x -= size[lson[k]];
    if (x <= c[k]) return ind[k]; //註意這裏是ind! 
    x -= c[k]; 
    return query_num(rson[k], x);
}

int main() {
    n = read(); m = read(); 
      for (int i = 1; i <= n; ++ i) {
        int x = read();
        val[x] = i;
        insert(root, i, x);
      }
      for (int i = 1; i <= m; ++ i) {
        scanf("%s", s + 1); 
        if (s[1] == 'Q') {
            int x = read();
            printf("%d\n", query_num(root, x));
          }
        else if (s[1] == 'T') {
          int x = read();
          del(root, val[x]);
          insert(root, 1 - i, x);
          val[x] = 1 - i;
        }
        else if (s[1] == 'B') {
          int x = read();
          del(root, val[x]);
          insert(root, n + i, x);
          val[x] = n + i;
        }
        else if (s[1] == 'A') {
          int x = read();
          printf("%d\n", query_rank(root, val[x]) - 1);
        }
        else if (s[1] == 'I') {
          int x = read(), y = read();
            if (y == 0) continue;
          int z = query_num(root, query_rank(root, val[x]) + y);
          del(root, val[x]);
          del(root, val[z]);
          insert(root, val[x], z);
          insert(root, val[z], x);
          swap(val[x], val[z]);
        }
      }
    return 0;
} 

bzoj1861: [Zjoi2006]Book 書架(平衡樹)