BZOJ3224 普通平衡树

Description

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)

Input

第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

Output

对于操作3,4,5,6每行输出一个数,表示对应答案
题解
这道题很明显要用二叉排序树来进行操作,其实是裸题。不过以前没打过splay,考试时教练让我们打splay。没打出来,调了一晚上也没调出来。wwwww。熬夜打了一个treap,还要上课啊。。。。。补觉了。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <ctime>
using namespace std;
const int Maxn = 101111;
struct node {
	int s,v,r,cnt; int ch[2];
}N[Maxn];
int totN, root;
const int INF = 1 << 30;
void up(int u) {
	int ls = N[u].ch[0], rs = N[u].ch[1];
	N[u].s = N[u].cnt + N[ls].s + N[rs].s;
}

void Rot(int &u, int d) {
	int t = N[u].ch[d^1];  N[u].ch[d^1] = N[t].ch[d];
	N[t].ch[d] = u;
	up(u); up(t); u = t;
}

void Ins(int& u,int val) {
	if (!u) {
		u = ++totN; N[u].v = val; N[u].cnt = 1; N[u].s = 1; N[u].r = rand();
	} else {
		++N[u].s; int k = val < N[u].v ? 0 : 1;
		if (N[u].v == val) { ++N[u].cnt; return; }
		Ins(N[u].ch[k], val);
		if (N[N[u].ch[k]].r > N[u].r) Rot(u, k ^ 1);
	}
}

void Del(int& u,int val) {
	if (!u) return;
	if (N[u].v == val) {
		if (N[u].cnt > 1) { --N[u].cnt; --N[u].s; return; }
		if (!N[u].ch[0] || !N[u].ch[1]) u = N[u].ch[0] + N[u].ch[1];
		else {
			int k = N[N[u].ch[0]].r > N[N[u].ch[1]].r;
			Rot(u,k); Del(u, val); 
		}
	} else --N[u].s, Del(N[u].ch[val < N[u].v ? 0 : 1],val);
}

int Rank(int u, int val) {
	if (!u) return 0;
	if (N[u].v == val) return N[N[u].ch[0]].s + 1;
	if (N[u].v < val) return N[N[u].ch[0]].s + N[u].cnt + Rank(N[u].ch[1],val);
	else return Rank(N[u].ch[0],val);
}

int Kth(int u,int k) {
	if (!u) return 0;
	if (k <= N[N[u].ch[0]].s) return Kth(N[u].ch[0],k);
	if (k > N[N[u].ch[0]].s + N[u].cnt) 
		return Kth(N[u].ch[1],k - N[N[u].ch[0]].s - N[u].cnt);
	return N[u].v;
}

int pred(int u, int val) {
	if (!u) return INF;
	if (val <= N[u].v) return pred(N[u].ch[0],val);
	int ans = pred(N[u].ch[1],val);
	if (ans == INF) ans = N[u].v;
	return ans;
}

int succ(int u, int val) {
	if (!u) return INF;
	if (val >= N[u].v) return succ(N[u].ch[1],val);
	int ans = succ(N[u].ch[0],val);
	if (ans == INF) ans = N[u].v;
	return ans;
}

int main() {
	//freopen("A.in","r",stdin);
	//freopen("A.out","w",stdout);
	int n, op, x;
	scanf("%d", &n);
	srand(time(NULL));
	while (n--) {
		scanf("%d%d", &op, &x);
		if (op == 1) Ins(root,x);
		else if (op == 2) Del(root,x);
		else if (op == 3) printf("%d\n", Rank(root,x));
		else if (op == 4) printf("%d\n", Kth(root,x));
		else if (op == 5) printf("%d\n", pred(root,x));
		else printf("%d\n",succ(root,x));
	}
	return 0;
}
附:在网上看见了一个模板,把splay,treap和SBT的做法打了出来。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值