[洛谷P3369]【模板】普通平衡树

题目大意:需要提供以下操作:

  1. 插入 $x$ 数
  2. 删除 $x$ 数(若有多个相同的数,应只删除一个)
  3. 查询 $x$ 数的排名(排名定义为比当前数小的数的个数 $+1$ 。若有多个相同的数,因输出最小的排名)
  4. 查询排名为 $x$ 的数
  5. 求 $x$ 的前驱(前驱定义为小于 $x$ ,且最大的数)
  6. 求 $x$ 的后继(后继定义为大于 $x$ ,且最小的数)

题解:平衡树,treap

卡点:

 

C++ Code:

 

#include <cstdio>
#include <cstdlib>
#define maxn 100050
using namespace std;
int n, op, x;
struct treap {
	int lc[maxn], rc[maxn], val[maxn], num[maxn], sz[maxn]; //val值,num堆值 
	int root, idx;
	int ta, tb, tmp, res;
	int update(int p) {
		sz[p] = sz[lc[p]] + sz[rc[p]] + 1;
		return p;
	}
	int nw(int p) {
		val[++idx] = p;
		sz[idx] = 1;
		num[idx] = rand();
		return idx;
	}
	void split(int rt, int k, int &x, int &y) {
		if (!rt) x = y = 0;
		else {
			if (val[rt] <= k) split(rc[rt], k, rc[rt], y), x = update(rt);
			else split(lc[rt], k, x, lc[rt]), y = update(rt);
		}
	}
	int merge(int x, int y) {
		if (!x || !y) return x|y;
		if (num[x] > num[y]) {rc[x] = merge(rc[x], y); return update(x);}
		else {lc[y] = merge(x, lc[y]); return update(y);}
	}
	void insert(int p) {
		if (!root) {
			root = nw(p);
		} else {
			split(root, p, ta, tb);
			root = merge(merge(ta, nw(p)), tb);
		}
	}
	void erase(int p) {
		split(root, p, ta, tb);
		split(ta, p - 1, ta, tmp);
		root = merge(ta, merge(merge(lc[tmp], rc[tmp]), tb));
	}
	int gtrnk(int p) {
		split(root, p - 1, ta, tb);
		res = sz[ta] + 1;
		root = merge(ta, tb);
		return res;
	}
	int gtk_th(int p, int k) {
		while (true) {
			if (sz[lc[p]] >= k) p = lc[p];
			else
				if (sz[lc[p]] + 1 == k) return val[p];
				else k -= sz[lc[p]] + 1, p = rc[p];
		}
	}
	int pre(int p) {
		split(root, p - 1, ta, tb);
		res = gtk_th(ta, sz[ta]);
		root = merge(ta, tb);
		return res;
	}
	int nxt(int p) {
		split(root, p, ta, tb);
		res = gtk_th(tb, 1);
		root = merge(ta, tb);
		return res;
	}
} T;

int main() {
	srand(20040826);
	scanf("%d", &n);
	while (n--) {
		scanf("%d%d", &op, &x);
		switch (op) {
			case 1: {
				T.insert(x);
				break;
			}
			case 2: {
				T.erase(x);
				break;
			}
			case 3: {
				printf("%d\n", T.gtrnk(x));
				break;
			}
			case 4: {
				printf("%d\n", T.gtk_th(T.root, x));
				break;
			}
			case 5: {
				printf("%d\n", T.pre(x));
				break;
			}
			case 6: {
				printf("%d\n", T.nxt(x));
				break;
			}
		}
	}
	return 0;
}

 

  

 

转载于:https://www.cnblogs.com/Memory-of-winter/p/9335214.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值