[bzoj1861][Zjoi2006]Book书架 splay

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 0x7fffffff
using 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
不搞混不同的变量(可称之为单位)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值