#26 [bzoj1861][Zjoi2006]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

Source

Day2

思维难度:NOIP+

代码难度:省选

算法:平衡树

#include<cstdio>
#include<iostream>
using namespace std;
const int Maxn=160005;
const int inf=160005;
int ch[Maxn][2],fa[Maxn],val[Maxn],sum[Maxn],root,maxn,minn,n,m;
inline void pushup(int rt){
	sum[rt]=sum[ch[rt][0]]+sum[ch[rt][1]]+1;
}
inline void rotate(int x){
	int y=fa[x],z=fa[y],k=ch[y][1]==x,w=ch[x][!k];
	if(z)ch[z][ch[z][1]==y]=x;ch[y][k]=w;ch[x][!k]=y;
	if(w)fa[w]=y;fa[y]=x;fa[x]=z;
	pushup(x);pushup(y);
}
inline void splay(int x){
	int y,z;
	while(fa[x]){
		y=fa[x],z=fa[y];
		if(z)rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y);
		rotate(x);
	}
	root=x;
}
inline int ranking(int x){
	splay(x);
	return sum[ch[x][0]];
}
inline int kth(int k){
	int x=root;
	while(1){
		if(sum[ch[x][0]]+1==k)return x;
		if(sum[ch[x][0]]+1>k)x=ch[x][0];
		else{
			k-=sum[ch[x][0]]+1;
			x=ch[x][1];
		} 
	}
}
inline int lower(int key){//这里是值!!不是编号!! 
	int x=root,ans=-inf,v;
	while(x){
		if(key<=val[x]){
			x=ch[x][0];
		}
		else{
			if(ans<val[x])ans=val[x],v=x; 
			x=ch[x][1];
		}
	} 
	return v;
}
inline int uper(int key){
	int x=root,ans=inf,v;
	while(x){
		if(key<val[x]){
			if(ans>val[x])ans=val[x],v=x;
			x=ch[x][0];
		}
		else{
			x=ch[x][1];
		}
	}
	return v;
}
inline void delet(int x){//x 是编号! 
	while(ch[x][0]||ch[x][1]){
		if(ch[x][0])rotate(ch[x][0]);
		else rotate(ch[x][1]);
	} 
	ch[fa[x]][ch[fa[x]][1]==x]=0;
	sum[x]=0;
	while(fa[x]){
		x=fa[x];
		pushup(x);
	}
	splay(x);
}
inline void build(int key,int id,int rt){
	if(key<val[rt]){
		if(!ch[rt][0]){
			ch[rt][0]=id;
			fa[id]=rt;
			pushup(rt);
			return;
		}
		build(key,id,ch[rt][0]);
	}
	else{
		if(!ch[rt][1]){
			ch[rt][1]=id;
			fa[id]=rt;
			pushup(rt);
			return;
		}
		build(key,id,ch[rt][1]);
	}
	pushup(rt);
}
inline void insert(int key,int id){
	sum[id]=1;val[id]=key;
	if(root==0){
		root=id;
		return;
	}
	build(key,id,root);
	splay(id);
}
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9'){
		if(c=='-')f=-1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		x=x*10+c-'0';
		c=getchar();
	}
	return x*f;
}
int main(){
	char s[15];int u,v,idx,x1,x2,cnt=0;
	n=read();m=read();maxn=n;minn=1;
	for(int i=1;i<=n;i++){
		u=read();
		insert(i,u);
	}
	for(int i=1;i<=m;i++){
		cin>>s;u=read();
		if(s[0]=='T'){
			delet(u);
			insert(minn=minn-1,u);
		}
		if(s[0]=='B'){
			delet(u);
			insert(maxn=maxn+1,u);
		}
		if(s[0]=='I'){
			v=read();
			if(v==-1){
				idx=lower(val[u]);
				x1=val[idx],x2=val[u];
				delet(u);delet(idx);insert(x1,u);insert(x2,idx);
			}
			if(v==1){
				idx=uper(val[u]);
				x1=val[idx],x2=val[u];
				delet(u);delet(idx);insert(x1,u);insert(x2,idx);
			}
		}
		if(s[0]=='A'){
			printf("%d\n",ranking(u));
		}
		if(s[0]=='Q'){
			printf("%d\n",kth(u));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/LvYanchang/article/details/81564180
今日推荐