[洛谷P3835]【模板】可持久化平衡树

题目大意:

来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):

  1. 插入x数

  2. 删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)

  3. 查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)

  4. 查询排名为x的数

  5. 求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)

  6. 求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)

和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)

每个版本的编号即为操作的序号(版本0即为初始状态,空树)

题解:可持久化平衡树,就是在merge和split的时候不修改原来的点,改为新增一个点存放

卡点:1.未考虑第一次插入因为树中没有节点,与其他的不同,需要特殊考虑,而导致后面出错

 

C++ Code:

#include <cstdio>
#include <cstdlib>
#define maxn 500010
using namespace std;
const int inf = 2147483647;
int n, ver, op, x;
int root[maxn];
struct Tree {
	int lc[maxn * 50], rc[maxn * 50], val[maxn * 50], num[maxn * 50], sz[maxn * 50]; //val值,num堆值 
	int idx, ta, tb, tmp, res;
	void debug(int p) {
		if (lc[p]) debug(lc[p]);
		printf("%d : val %d  lc %d  rc %d\n", p, val[p], lc[p], rc[p]);
		if (rc[p]) debug(rc[p]);
	}
	void cpy(int cur, int ver) {
		lc[cur] = lc[ver];
		rc[cur] = rc[ver];
		val[cur] = val[ver];
		num[cur] = num[ver];
		sz[cur] = sz[ver];
	}
	void update(int rt) {sz[rt] = sz[lc[rt]] + sz[rc[rt]] + 1;}
	int nw(int p) {
		val[++idx] = p;
		sz[idx] = 1;
		num[idx] = rand();
		return idx;
	}
	void split(int rt, int p, int &x, int &y) {
		if (!rt) x = y = 0;
		else {
			if (val[rt] <= p) {
				x = ++idx;
				cpy(x, rt);
				split(rc[x], p, rc[x], y);
				update(x);
			} else {
				y = ++idx;
				cpy(y, rt);
				split(lc[y], p, x, lc[y]);
				update(y);
			}
		}
	}
	int merge(int x, int y) {
		if (!x || !y) return x | y;
		int o;
		if (num[x] < num[y]) {
			o = ++idx;
			cpy(o, x);
			rc[o] = merge(rc[o], y);
		} else {
			o = ++idx;
			cpy(o, y);
			lc[o] = merge(x, lc[o]);
		}
		update(o);
		return o;
	}
	void insert(int &rt, int x) {
		if (!rt) rt = nw(x);
		else {
			split(rt, x, ta, tb);
	//		printf("Debug:%d %d\n", ta, tb);
			rt = merge(merge(ta, nw(x)), tb);
		}
	}
	void erase(int &rt, int x) {
		split(rt, x, ta, tb);
		split(ta, x - 1, ta, tmp);
//		printf("%d %d %d\n", ta, tb, tmp);
		if (val[tmp] != x) rt = merge(merge(ta, tmp), tb);
		else rt = merge(merge(ta, merge(lc[tmp], rc[tmp])), tb);
	}
	int gtrnk(int rt, int x) {
		split(rt, x - 1, ta, tb);
		res = sz[ta] + 1;
		merge(ta, tb);
		return res;
	}
	int gtkth(int rt, int k) {
		while (true) {
			if (k <= sz[lc[rt]]) rt = lc[rt];
			else {
				if (k == sz[lc[rt]] + 1) return val[rt];
				else k -= sz[lc[rt]] + 1, rt = rc[rt];
			}
		}
	}
	int pre(int rt, int x) {
		split(rt, x - 1, ta, tb);
		if (!ta) res = -inf;
		else res = gtkth(ta, sz[ta]), merge(ta, tb);
		return res;
	}
	int nxt(int rt, int x) {
		split(rt, x, ta, tb);
		if (!tb) res = inf;
		else res = gtkth(tb, 1), merge(ta, tb);
		return res;
	}
} T;
int main() {
	srand(20040826);
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d%d%d", &ver, &op, &x);
		root[i] = root[ver];
		switch (op) {
			case 1: {
				T.insert(root[i], x); 
//				T.debug(root[i]);
				break;
			}
			case 2: {
				T.erase(root[i], x); 
//				T.debug(root[i]);
				break;
			}
			case 3: {
				printf("%d\n", T.gtrnk(root[i], x)); 
//				T.debug(root[i]);
				break;
			}
			case 4: {
				printf("%d\n", T.gtkth(root[i], x)); 
//				T.debug(root[i]);
				break;
			}
			case 5: {
				printf("%d\n", T.pre(root[i], x)); 
//				T.debug(root[i]);
				break;
			}
			case 6: {
				printf("%d\n", T.nxt(root[i], x)); 
//				T.debug(root[i]);
				break;
			}
		}
	}
	return 0;
} 

  

posted @ 2018-07-23 15:36  Memory_of_winter  阅读(195)  评论(0编辑  收藏  举报