bzoj1861 [Zjoi2006]Book 书架
1861: [Zjoi2006]Book 书架
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 1988 Solved: 1122
[Submit][Status][Discuss]
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
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
9
9
7
5
3
HINT
数据范围
Source
分析:数据结构题的既视感......
用splay来维护,维护的是“位置”.那么在插入的时候不能按照书的编号进行插入,而是按照书的位置,也就是当前的书是第几小的.这样我们就要维护一个size数组,代表以i为根的子树有多少个节点.因为splay节点记录的是书的编号,并不是次序,所以需要利用size数组来知道当前节点代表的次序是多少.每次将当前要插入的次序与左子节点代表的次序相比较.
对于前三种操作,其实就是查询+删除+插入的结合体.查询是需要查编号为S的书在splay上节点是哪一个,删除就是将原来的点删掉.并维护一个pos数组,表示编号为S的书在splay上节点是哪一个,进行完每次操作后都要更新pos数组.对于第四个操作,将S旋转到根节点上,那么左子树的大小就是答案.第五个操作则利用size数组不断地缩小范围,最后可以锁定到一个元素上.
需要关注的是size数组的维护.在每次删除,插入和左右旋都要修改被改变的点的size值.
数组要开大点,一开始一直RE以为访问到了无效节点......
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 1000010; int n,m,sizee[maxn],pos[maxn],tot,root,a[maxn]; struct node { int fa,left,right,v; } e[maxn]; void update(int x) { sizee[x] = 1; if (e[x].left != -1) sizee[x] += sizee[e[x].left]; if (e[x].right != -1) sizee[x] += sizee[e[x].right]; } int getsize(int x) { if (x == -1) return 0; return sizee[x]; } void turnr(int x) { int y = e[x].fa; int z = e[y].fa; e[y].left = e[x].right; if (e[x].right != -1) e[e[x].right].fa = y; e[x].fa = z; if (z != -1) { if (e[z].left == y) e[z].left = x; else e[z].right = x; } e[x].right = y; e[y].fa = x; update(y); update(x); } void turnl(int x) { int y = e[x].fa; int z = e[y].fa; e[y].right = e[x].left; if (e[x].left != -1) e[e[x].left].fa = y; e[x].fa = z; if (z != -1) { if (e[z].left == y) e[z].left = x; else e[z].right = x; } e[x].left = y; e[y].fa = x; update(y); update(x); } void splay(int x) { while (e[x].fa != -1) { int y = e[x].fa; int z = e[y].fa; if (z == -1) { if (x == e[y].left) turnr(x); else turnl(x); } else { if (e[z].left == y && e[y].left == x) { turnr(y); turnr(x); } else { if (e[z].right == y && e[y].right == x) { turnl(y); turnl(x); } else { if (e[z].left == y && e[y].right == x) { turnl(x); turnr(x); } else { turnr(x); turnl(x); } } } } } root = x; } void del(int x) { splay(x); if (e[x].left == -1 && e[x].right == -1) { root = -1; return; } if (e[x].left == -1) { root = e[x].right; e[e[x].right].fa = -1; return; } if (e[x].right == -1) { root = e[x].left; e[e[x].left].fa = -1; return; } int j = e[x].left; while (e[j].right != -1) j = e[j].right; splay(j); e[j].right = e[x].right; e[e[x].right].fa = j; root = j; update(j); } void insert(int x,int y,int k) { if (k == 1 && e[x].left == -1) { e[x].left = ++tot; e[tot].left = e[tot].right = -1; e[tot].fa = x; e[tot].v = y; return; } if (k == 2 + getsize(e[x].left) && e[x].right == -1) { e[x].right = ++tot; e[tot].left = e[tot].right = -1; e[tot].fa = x; e[tot].v = y; return; } if (k <= 1 + getsize(e[x].left)) insert(e[x].left,y,k); else insert(e[x].right,y,k - 1 - getsize(e[x].left)); update(x); } int query(int k,int p) { int x = p; while (1) { if (k == 1 + getsize(e[x].left)) return x; if (k > 1 + getsize(e[x].left)) { k -= 1 + getsize(e[x].left); x = e[x].right; } else x = e[x].left; } } int query2(int x) { if (x == -1) return 0; splay(x); return getsize(e[x].left) + 1; } int main() { scanf("%d%d",&n,&m); for (int i = 1; i <= n; i++) scanf("%d",&a[i]); pos[a[1]] = 1; root = ++tot; sizee[tot] = 1; e[tot].fa = e[tot].left = e[tot].right = -1; e[tot].v = a[1]; for (int i = 2; i <= n; i++) { pos[a[i]] = i; insert(root,a[i],i); splay(tot); } for (int i = 1; i <= m; i++) { char s[10]; int x,y; scanf("%s",s + 1); if (s[1] == 'Q') { scanf("%d",&x); printf("%d\n",e[query(x,root)].v); } if (s[1] == 'T') { scanf("%d",&x); del(pos[x]); insert(root,x,1); pos[x] = tot; splay(tot); } if (s[1] == 'B') { scanf("%d",&x); del(pos[x]); insert(root,x,n); pos[x] = tot; splay(tot); } if (s[1] == 'A') { scanf("%d",&x); printf("%d\n",query2(pos[x]) - 1); } if (s[1] == 'I') { scanf("%d%d",&x,&y); int u = query2(pos[x]); del(pos[x]); u = u + y; insert(root,x,u); splay(tot); pos[x] = tot; } } return 0; }