【luogu P3369】普通平衡树(fhq Treap 做法)

普通平衡树

题目链接:luogu P3369

题目大意

平衡树模板题,要求维护一些操作。 插入一个数,删除一个数,查询一个数的排名,查询排名一直的数,找前驱后继。

思路

这次我们用 fhq Treap(无旋 Treap)来做。

无旋 Treap 就是搞把树分裂与合并来实现对堆和二叉排序树的维护。

然后这里讲一下一些操作的实现。
插入输出很好想,两种排名也好搞。
而找前驱可以先按这个数割树,这个数放在右边,然后左边的树一直往右走。
而找后继可以先按这个数 \(+1\) 个数,使得这个数放在左边的最右边,然后右边的树一直往左走。

具体实现可以看看代码。

代码

#include<queue>
#include<cstdio>
#include<cstdlib>

using namespace std;

int ls[100001], rs[100001], val[100001], yj[100001], sz[100001], sum[100001];
int n, op, x, tot, root;

int make_new(int num) {
	int now = ++tot;
	sz[now] = 1;
	ls[now] = rs[now] = 0;
	val[now] = num;
	yj[now] = rand();
	return now;
}

void up(int now) {
	sz[now] = sz[ls[now]] + sz[rs[now]] + 1;
}

pair <int, int> split_rnk(int now, int rnk) {
	if (!now) return make_pair(0, 0);
	if (!rnk) return make_pair(0, now);
	
	pair <int, int> re;
	if (sz[ls[now]] >= rnk) {
		re = split_rnk(ls[now], rnk);
		ls[now] = re.second;
		up(now);
		re.second = now;
	}
	else {
		re = split_rnk(rs[now], rnk - sz[ls[now]] - 1);
		rs[now] = re.first;
		up(now);
		re.first = now;
	}
	
	return re;
}

pair <int, int> split_val(int now, int num) {
	if (!now) return make_pair(0, 0);
	
	pair <int, int> re;
	if (num <= val[now]) {
		re = split_val(ls[now], num);
		ls[now] = re.second;
		up(now);
		re.second = now;
	}
	else {
		re = split_val(rs[now], num);
		rs[now] = re.first;
		up(now);
		re.first = now;
	}
	
	return re;
}

int merge(int x, int y) {
	if (!x) return y;
	if (!y) return x;
	
	if (yj[x] < yj[y]) {
		rs[x] = merge(rs[x], y);
		up(x);
		return x;
	}
	else {
		ls[y] = merge(x, ls[y]);
		up(y);
		return y;
	}
}

void insert(int x) {
	int now = make_new(x);
	pair <int, int> y = split_val(root, x);
	root = merge(merge(y.first, now), y.second);
}

void delete_(int now) {
	pair <int, int> x = split_val(root, now);
	pair <int, int> y = split_rnk(x.second, 1);
	root = merge(x.first, y.second);
}

int ask_rnk(int now) {
	pair <int, int> x = split_val(root, now);
	int re = sz[x.first] + 1;
	root = merge(x.first, x.second);
	return re;
}

int ask_val(int now) {
	pair <int, int> x = split_rnk(root, now - 1);
	pair <int, int> y = split_rnk(x.second, 1);
	int re = val[y.first];
	root = merge(x.first, merge(y.first, y.second));
	return re;
}

int get_pre(int now) {
	pair <int, int> x = split_val(root, now);
	int X = x.first, Y = 0;
	while (X) {
		Y = X;
		X = rs[X];
	}
	root = merge(x.first, x.second);
	return val[Y];
}

int get_nxt(int now) {
	pair <int, int> x = split_val(root, now + 1);
	int X = x.second, Y = 0;
	while (X) {
		Y = X;
		X = ls[X];
	}
	root = merge(x.first, x.second);
	return val[Y];
}

int main() {
	srand(1919810);
	
	scanf("%d", &n);
	while (n--) {
		scanf("%d %d", &op, &x);
		
		if (op == 1) {
			insert(x);
			continue;
		}
		if (op == 2) {
			delete_(x);
			continue;
		}
		if (op == 3) {
			printf("%d\n", ask_rnk(x));
			continue;
		}
		if (op == 4) {
			printf("%d\n", ask_val(x));
			continue;
		}
		if (op == 5) {
			printf("%d\n", get_pre(x));
			continue;
		}
		if (op == 6) {
			printf("%d\n", get_nxt(x));
			continue;
		}
	}
	
	return 0;
}
posted @ 2021-05-24 20:45  あおいSakura  阅读(80)  评论(0编辑  收藏  举报