zoukankan      html  css  js  c++  java
  • 【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
    ", s[c[id[a]][0]]);
    118                 break;
    119             case 'Q':
    120                 printf ("%d
    ", ask (root, a));
    121                 break;
    122         }
    123     }
    124 }
  • 相关阅读:
    [微软认证]MCP问题解答
    邮件服务
    QueryString 整站过滤
    今天开始安卓的底层开发吧。
    所谓的回调函数
    UTF8 to unicode
    TCP/IP中的拥塞窗口控制机制
    (转)前端页面,页内锚定位分析
    远程连接Sql Server 2008 R2 命名实例
    字符编码研究
  • 原文地址:https://www.cnblogs.com/lightning34/p/4324320.html
Copyright © 2011-2022 走看看