[bzoj1861][Zjoi2006]Book书架 splay

来源:互联网 发布:知聊可以提现吗 编辑:程序博客网 时间:2024/05/16 12:45

1861: [Zjoi2006]Book 书架

Time Limit: 4 Sec  Memory Limit: 64 MB
[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

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

Source

按下标建splay,因为要移动所以其他朴素的平衡树是不行的,我不会可持久化

Top       把编号为S的书放在最上面

Bottom 把编号为S的书放在最下面

Insert    把编号为S的书前移、后移或者不动

Ask       询问编号为S的书上面有多少本书

Query   询问第S本书的编号

改变的话,只用删掉原来的点,再在那个位置加上就可以了
然后就是裸的平衡树了
#include<iostream>#include<cstdio>#define inf 0x7fffffffusing namespace std;const int N = 80000 + 5;int n,m,root,S,T; char ch[10];int c[N][2],siz[N],pos[N],v[N],fa[N],a[N];void update( int k ){siz[k] = siz[c[k][0]] + siz[c[k][1]] + 1;}void rotate( int x, int &k ){int y = fa[x], z = fa[y], l, r;l = c[y][0]!=x; r = l^1;if( y == k ) k = x;else c[z][c[z][1]==y] = x;fa[x] = z; fa[y] = x; fa[c[x][r]] = y;c[y][l] = c[x][r]; c[x][r] = y;update(y); update(x);}void splay( int x, int &k ){while( x != k ){int y = fa[x], z = fa[y];if( y != k ){if( x==c[y][0]^y==c[z][0] ) rotate(x,k);else rotate(y,k);}rotate(x,k);}}void build( int l, int r, int f ){if( l > r ) return ;if( l == r ){v[l] = a[l]; siz[l] = 1; fa[l] = f;c[f][l>=f] = l; return ;}int mid = (l+r)>>1;build( l, mid-1, mid ); build( mid+1, r, mid );v[mid] = a[mid]; fa[mid] = f; update(mid);c[f][mid>=f] = mid;}int find( int x, int rank ){if( siz[c[x][0]]+1 == rank ) return x;if( siz[c[x][0]] >= rank ) return find(c[x][0],rank);return find(c[x][1],rank-siz[c[x][0]]-1);}void del( int k ){int x = find(root,k-1), y = find(root,k+1);splay(x,root); splay(y,c[x][1]);fa[c[y][0]] = siz[c[y][0]] = 0; c[y][0] = 0;update(y); update(x);}void move( int k, int flag ){int x,y,p = pos[k],rk;splay(p,root); rk = siz[c[p][0]]+1; del(rk);if( flag == inf ) x = find(root,n), y = find(root,n+1);else if( flag == -inf ) x = find(root,1), y = find(root,2);else x = find(root,rk+flag-1), y = find(root,rk+flag);splay( x, root ); splay( y, c[x][1] );siz[p] = 1; fa[p] = y; c[y][0] = p;update(y); update(x);}int main(){scanf("%d%d", &n, &m); a[1] = -inf; a[n+2] = inf;for( int i = 1; i <= n; i++ ) scanf("%d", &a[i+1]), pos[a[i+1]] = i+1;build(1,n+2,0); root = (n+3)>>1;while( m-- ){scanf("%s", ch); scanf("%d", &S );if( ch[0] == 'T' ) move(S,-inf);if( ch[0] == 'B' ) move(S, inf);if( ch[0] == 'I' ) scanf("%d", &T), move(S,T);if( ch[0] == 'A' ) splay(pos[S],root), printf("%d\n",siz[c[pos[S]][0]]-1);if( ch[0] == 'Q' ) printf("%d\n",v[find(root,S+1)]);}return 0;}

总结
搞清三个变量之间的关系,pos套a指树上编号,v套pos指a
不搞混不同的变量(可称之为单位)