☆ [ZJOI2006] 书架 「平衡树维护数列」

题目类型:平衡树

传送门:>Here<

题意:要求维护一个数列,支持:将某个元素置顶或置底,交换某元素与其前驱或后继的位置,查询编号为\(S\)的元素的排名,查询排名第\(k\)的元素编号

解题思路

可以说是平衡树维护数列的入门题。当平衡树在维护数列时,关键字是在数列中的排名。因此中序遍历即为当前数列。注意在平衡树维护数列中,会涉及到两个编号。一个编号是这个节点在平衡树内的编号,一般外界是不会直接访问的。另一个是题目赋予的编号,代表这个位置数列上对应的值。外部编号即为一个附加值。当我们需要找到外部编号为\(S\)的元素,好像比较麻烦。此时,我们需要多开一个数组\(pos\),令\(pos[idx[o]]=o\),相当于是\(idx\)数组的逆运算。在知道一个外部编号时,能够迅速找到其所对应的节点编号。然后就可以对其进行直接操作了

至于前驱后继交换,我们只需要交换这两个节点所对应的外部编号以及更新\(pos\),没有必要交换平衡树内的节点。

Code

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define  r  read()
using namespace std;
typedef long long ll;
const int MAXN = 80010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int N,M,S,T;
char opt[10];
int idx[MAXN],pos[MAXN];
struct Splay{
	int fa[MAXN],ch[MAXN][2],size[MAXN],num_node,rt;
	inline void update(int x){
		size[x] = 1;
		if(ch[x][0]) size[x] += size[ch[x][0]];
		if(ch[x][1]) size[x] += size[ch[x][1]];
	}
	inline bool rson(int f, int x){
		return ch[f][1] == x;
	}
	inline void rotate(int x){
		int f = fa[x], gf = fa[f];
		bool p = rson(f, x), q = !p;
		if(!gf) rt = x; else ch[gf][rson(gf,f)] = x;
		fa[x] = gf;
		ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
		ch[x][q] = f, fa[f] = x;
		update(f), update(x);
	}
	inline void splay(int x, int target){
		int f,gf;
		while(fa[x] != target){
			f = fa[x], gf = fa[f];
			if(gf == target){
				rotate(x);
				break;
			}
			if(rson(gf,f) ^ rson(f,x)) rotate(x); else rotate(f);
			rotate(x);
		}
	}
	inline void init(int id){
		if(!rt){
			rt = ++num_node;
			idx[num_node] = id;
			pos[id] = num_node;
			size[num_node] = 1;
			return;
		}
		int pre_rt = rt;
		rt = ++num_node;
		ch[rt][0] = pre_rt;
		fa[pre_rt] = rt;
		size[rt] = size[pre_rt] + 1;
		idx[rt] = id;
		pos[id] = rt;
	}
	inline void top(int s){
		int o = pos[s];
		splay(o, 0);
		if(!ch[rt][0] && !ch[rt][1]) return;
		int p = ch[rt][1];
		if(!p){
			ch[rt][1] = ch[rt][0];
			ch[rt][0] = 0;
			splay(ch[rt][1], 0);
			return;
		}
		while(ch[p][0]) p = ch[p][0];
		splay(p, rt);
		ch[p][0] = ch[rt][0];
		fa[ch[rt][0]] = p;
		ch[rt][0] = 0;
		update(p), update(rt);
	}
	inline void bottom(int s){
		int o = pos[s];
		splay(o, 0);
		if(!ch[rt][0] && !ch[rt][1]) return;
		int p = ch[rt][0];
		if(!p){
			ch[rt][0] = ch[rt][1];
			ch[rt][1] = 0;
			splay(ch[rt][0], 0);
			return;
		}
		while(ch[p][1]) p = ch[p][1];
		splay(p, rt);
		ch[p][1] = ch[rt][1];
		fa[ch[rt][1]] = p;
		ch[rt][1] = 0;
		update(p), update(rt);
	}
	inline int ask(int s){
		int o = pos[s];
		splay(o, 0);
		return size[ch[rt][0]];
	}
	inline int query(int k){
		int o = rt;
		while(o){
			if(size[ch[o][0]] >= k){
				o = ch[o][0];
			}
			else if(size[ch[o][0]] + 1 < k){
				k -= size[ch[o][0]] + 1;
				o = ch[o][1];
			}
			else{
				return idx[o];
			}
		}
		return -1;
	}
	inline void insert(int S, int T){
		if(T == 0) return;
		splay(pos[S], 0);
		if(T == -1){
			int o = ch[rt][0];
			while(ch[o][1]) o = ch[o][1];
			splay(o, rt);
			swap(idx[rt], idx[o]);
			pos[idx[rt]] = rt, pos[idx[o]] = o;
			update(o), update(rt);
		}
		if(T == 1){
			int o = ch[rt][1];
			while(ch[o][0]) o = ch[o][0];
			splay(o, rt);
			swap(idx[rt], idx[o]);
			pos[idx[rt]] = rt, pos[idx[o]] = o;
			update(o), update(rt);
		}
	}
}qxz;
int main(){
	scanf("%d %d", &N, &M);
	for(int i = 1; i <= N; ++i){
		scanf("%d", &S);
		qxz.init(S);
	} 
	while(M--){
		scanf("%s %d", opt, &S);
		if(opt[0] == 'T'){
			qxz.top(S);
		}
		if(opt[0] == 'B'){
			qxz.bottom(S);
		}
		if(opt[0] == 'A'){
			printf("%d\n", qxz.ask(S));
		}
		if(opt[0] == 'Q'){
			printf("%d\n", qxz.query(S));
		}
		if(opt[0] == 'I'){
			scanf("%d", &T);
			qxz.insert(S,T);
		}
	}
}
posted @ 2018-09-16 08:04  行而上  阅读(196)  评论(0)    收藏  举报