【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 }
时间: 2025-01-17 22:58:56

【BZOJ 1861】Book 书架的相关文章

[题解]bzoj 1861 Book 书架 - Splay

1861: [Zjoi2006]Book 书架 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1396  Solved: 803[Submit][Status][Discuss] Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位

BZOJ 1861: [Zjoi2006]Book 书架 (splay)

1861: [Zjoi2006]Book 书架 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 1453  Solved: 822[Submit][Status][Discuss] Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位

BZOJ 1861: [Zjoi2006]Book 书架 splay

1861: [Zjoi2006]Book 书架 Description 小T有一个很大的书柜.这个书柜的构造有些独特,即书柜里的书是从上至下堆放成一列.她用1到n的正整数给每本书都编了号. 小T在看书的时候,每次取出一本书,看完后放回书柜然后再拿下一本.由于这些书太有吸引力了,所以她看完后常常会忘记原来是放在书柜的什么位置.不过小T的记忆力是非常好的,所以每次放书的时候至少能够将那本书放在拿出来时的位置附近,比如说她拿的时候这本书上面有X本书,那么放回去时这本书上面就只可能有X-1.X或X+1本

BZOJ 1861 ZJOI 2006 Book 书架 Splay

题目大意:有一个书架,现在需要经常改变这些书的位置,每次询问一本书在哪或者第几本书是什么. 思路:赤裸裸的Splay,只是有些小事需要注意.因为他有的时候问你一个书在哪,这个事情不能只在Splay中就能解决,我们需要辅助他解决.注意到操作中没有加入书的操作,也就是书的总数并不会变化,而且Splay的过程中只是指针的变动,所以不会有点发生变化,所以在一开始建树的时候维护一个数组,表示这本书在Splay中的节点,这样我们就能快速的找到任意一本书的节点.询问一本书的排名的时候,我们需要先找到这个节点,

BZOJ 1861 [Zjoi2006]Book 书架 ——Splay

[题目分析] 模板题目. 首尾两个虚拟结点,十分方便操作. [代码] #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <map> #include <set> #include <queue> #include <string> #include <iostream> #include

BZOJ 1861 书架

(╯-_-)╯╧╧ 此处为错误代码. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 300050 #define inf 2147483646 using namespace std; int n,m,a[maxn],x,y; int tree[maxn][3],size[maxn],fath[maxn],val[maxn],roo

bzoj 1861

就是将区间上的点移位,用2次rev的话代码量降下来了(orzLSJ build忘记return...然而本地测试居然没事?卡了好久挺不值啊

【刷题】BZOJ 1926 [Sdoi2010]粟粟的书架

Description 幸福幼儿园 B29 班的粟粟是一个聪明机灵.乖巧可爱的小朋友,她的爱好是画画和读书,尤其喜欢 Thomas H. Cormen 的文章.粟粟家中有一个 R行C 列的巨型书架,书架的每一个位置都摆有一本书,上数第i 行.左数第j 列摆放的书有Pi,j页厚.粟粟每天除了读书之外,还有一件必不可少的工作就是摘苹果,她每天必须摘取一个指定的苹果.粟粟家果树上的苹果有的高.有的低,但无论如何凭粟粟自己的个头都难以摘到.不过她发现, 如果在脚下放上几本书,就可以够着苹果:她同时注意到

AC日记——[Sdoi2010]粟粟的书架 bzoj 1926

1926 思路: 主席树+二分水题: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 500005 #define maxr 205 #define maxn_ maxn*13 #define FalseAns "Poor QLW" int n,m,q,lc[maxn_],rc[maxn_],num[maxn_],ci[maxn_],tot,root[maxn]; int ai[maxn],bi[