【BZOJ 1861】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

数据范围

100%的数据,n,m < = 80000
 
分析:
  先看到数据范围80000,很明显要求的时间复杂度是O(NlogN),很快想到是用二叉树结构。
  题目中Top和Bottom功能,可以把节点从树中删除,再把树变成它的左儿子或右儿子,这样它就是最顶上或最底下的了。Insert功能,可以看作是把节点和它的前驱或后继调换位置。Ask操作就是把节点旋到根,看它左儿子的大小。Query就是直接找第k小的节点。
  刚看到这到题的时候,第i本书我直接用树的第i个节点来表示,以为这样会方便,实际上写起来很麻烦,规规矩据地写插入删除是可以的(第一次写过了,但是代码非常长,时间效率也不高,或许是我写的不好),但是实际上那样代码还是挺复杂的,如果就根据题目给的要求写函数,又不好调(这是第二次写的,没调好),所以只好重写一次。
  最后就重新又写了一边,用一个数组id[i]来表示第i本书对应树上的节点,这样就轻松愉快多了。
  (据说这道题可以直接调用stl。。QAQ)
 
代码:
  1 #include <cstdio>
  2 #define mx 200000
  3 int n, m, a, b, bk[mx], id[mx];
  4 char str[10];
  5 int f[mx], c[mx][2], s[mx], k[mx], size, root;
  6 
  7 inline void pushup (int x)
  8 {
  9     s[x] = s[c[x][0]] + s[c[x][1]] + 1;
 10 }
 11 
 12 inline int rotate (int i)
 13 {
 14     int fa = f[i], d = (c[fa][1] == i);
 15     f[i] = f[fa], fa > 0 ? c[f[fa]][c[f[fa]][1] == fa] = i : 0;
 16     (c[fa][d] = c[i][!d]) ? f[c[i][!d]] = fa : 0;
 17     pushup (c[f[fa] = i][!d] = fa);
 18     return i;
 19 }
 20 
 21 inline void splay (int i, int p)
 22 {
 23     for (int fa = f[i]; fa != p; fa = f[rotate (i)])
 24         f[fa] != p ? rotate (c[fa][1] == i ^ c[f[fa]][1] == fa ? i : fa): 0;
 25     pushup (i);
 26     if (f[i] == 0) root = i;
 27 }
 28 
 29 int build (int fa, int l, int r)
 30 {
 31     if (l > r) return 0;
 32     int m = (l + r) >> 1;
 33     int i = ++size;
 34     f[i] = fa;
 35     k[i] = bk[m];
 36     id[bk[m]] = i;
 37     c[i][0] = build (i, l, m - 1);
 38     c[i][1] = build (i, m + 1, r);
 39     pushup (i);
 40     return i;
 41 }
 42 
 43 int check (int t, int i)
 44 {
 45     if (c[i][t] == 0) return i;
 46     return check (t, c[i][t]);
 47 }
 48 
 49 int ask (int i, int key)
 50 {
 51     int t = s[c[i][0]];
 52     if (key <= t) return ask (c[i][0], key);
 53     if (key > t + 1) return ask (c[i][1], key - t - 1);
 54     return k[i];
 55 }
 56 
 57 void exchange (int t, int i)
 58 {
 59     splay (i, 0);
 60     if (c[i][t] == 0) return;
 61     int x = check (!t, c[i][t]);
 62     k[i] ^= k[x];
 63     k[x] ^= k[i];
 64     k[i] ^= k[x]; // swap
 65     id[k[i]] = i;
 66     id[k[x]] = x;
 67 }
 68 
 69 void move (int t, int i)
 70 {
 71     splay (i, 0);
 72     if (c[i][1] > 0)
 73     {
 74         int x = check (0, c[i][1]);
 75         splay (x, i);
 76         c[x][0] = c[i][0];
 77         f[c[x][0]] = x;
 78         pushup (x);
 79         root = x;
 80     }else
 81     {
 82         f[c[i][0]] = 0;
 83         root = c[i][0];
 84     }
 85     f[i] = c[i][0] = c[i][1] = 0;
 86     f[root] = i;
 87     c[i][t] = 0;
 88     c[i][!t] = root;
 89     pushup (i);
 90     root = i;
 91     splay (i, 0);
 92 }
 93 
 94 int main ()
 95 {
 96     scanf ("%d %d", &n, &m);
 97     for (int i = 1; i <= n; i++)
 98         scanf ("%d", &bk[i]);
 99     root = build (0, 1, n);
100     for (int i = 0; i < m; i++)
101     {
102         scanf ("%s %d", str, &a);
103         switch (str[0])
104         {
105             case 'T':
106                 move (0, id[a]);
107                 break;
108             case 'B':
109                 move (1, id[a]);
110                 break;
111             case 'I':
112                 scanf ("%d", &b);
113                 if (b != 0) exchange (b == 1, id[a]);
114                 break;
115             case 'A':
116                 splay (id[a], 0);
117                 printf ("%d\n", s[c[id[a]][0]]);
118                 break;
119             case 'Q':
120                 printf ("%d\n", ask (root, a));
121                 break;
122         }
123     }
124 }

 

posted @ 2015-03-09 19:07  Lightning34  阅读(319)  评论(0编辑  收藏  举报