平衡树Treap

Treap每个节点的数据域包含2个值,key和weight。

key值,和原来的二叉搜索树一样,满足左子树<根节点<右子树。

weight值,随机产生。在Treap中weight值满足堆的性质,根节点的weight值小于等于(或大于等于)左右儿子节点。

比如下图就是一个示例的Treap:

输入

第1行:1个正整数n,表示操作数量,10≤n≤100,000

第2..n+1行:每行1个字母c和1个整数k:

若c为'I',表示插入一个数字k到树中,-1,000,000,000≤k≤1,000,000,000

若c为'Q',表示询问树中不超过k的最大数字

输出

若干行:每行1个整数,表示针对询问的回答,保证一定有合法的解

样例输入
5
I 3
I 2
Q 3
I 5
Q 4
样例输出
3
3
解析:题目意思是动态插入一些数字到树中,然后查找小于查询数字的最大值,通过建立一棵平衡树,来保存这些数字,利用随机值来 调整二叉树的形状使得在大部分情况下比直接通过数据建立的二叉树要平衡。每一次查找的期望复杂度也会降低,总体的速度也就得到了提高。

特别注意的地方是,查找时,当查询数字小于当前节点的key值时,且当前节点没有左孩子,需要返回当前节点在先序遍历中的直接前驱,可以尝试写个返回该前驱的方法,本文中使用全局变量直接保存查找中的目标值,只有在输入确保有合法解的情况下才有效。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <ctime>
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;

int radom()
{
	int a = 0;
	int b = 100010;
	srand((unsigned)time(NULL));
	return (rand() % (b - a + 1)) + a;
}

//平衡树Treap
struct node
{
	node(int k)
	{
		father = left = right = NULL;
		key = k;
		weight = radom();
	}
	int key, weight;
	node *father, *left, *right;
}*root;

int ans = 0;

void left_rotate(node* a)
{
	node* b = a->right;
	if (a->father == NULL)
	{
		root = b;
	}
	else
	{
		b->father = a->father;
		if (a->father->left == a)
			a->father->left = b;
		else
			a->father->right = b;
	}
	a->right = b->left;
	b->left->father = a;
	b->left = a;
	a->father = b;
}

void right_rotate(node* a)
{
	node* b = a->left;
	if (a->father == NULL)
	{
		root = b;
	}
	else
	{ 
		b->father = a->father;
		if (a->father->left == a)
			a->father->left = b;
		else
			a->father->right = b;
	}

	a->left = b->right;
	b->right->father = a;
	b->right = a;
	a->father = b;
}

node* insert(node* n, int key)
{
	if (key < n->key)
	{
		if (n->left == NULL)
		{
			n->left = new node(key);
			n->left->father = n;
			return n->left;
		}
		else
			return insert(n->left, key);
	}
	else
	{
		if (n->right == NULL)
		{
			n->right = new node(key);
			n->right->father = n;
			return n->right;
		}
		else
			return insert(n->right, key);
	}
}

void rotate(node* n)//完成插入后,根据weight旋转调节
{
	while (n->father != NULL)
	{
		node* fa = n->father;
		if (n->weight < fa->weight)//采用小根堆
		{
			if (n == fa->left)
				right_rotate(fa);
			else
				left_rotate(fa);
		}
		else
			break;
	}
}

node* find(int key)
{
	node* n = root;
	while (n != NULL)
	{
		if (key == n->key)
			return n;
		else if (key < n->key)
		{
			if (n->left != NULL)
				n = n->left;
			else
				return NULL;
		}
		else
		{
			if (n->right != NULL)
			{
				ans = max(ans, n->key);
				n = n->right;
			}
			else
				return n;
		}
	}
	return NULL;
}

void del(int key)//没用到
{
	node* n = find(key);
	while (n->left != NULL && n->right != NULL)//当有两个孩子时,循环旋转
	{
		node* child = n->left;
		if (child->weight>n->right->weight)
			child = n->right;

		if (child == n->left)
			right_rotate(n);
		else
			left_rotate(n);
	}
	//当只有一个或没有孩子时,执行删除操作
	node* fa = n->father;
	if (n->left != NULL)
	{
		n->left->father = fa;
		if (n == fa->left)
			fa->left = n->left;
		else
			fa->right = n->left;
	}
	else if (n->right != NULL)
	{
		n->right->father = fa;
		if (n == fa->left)
			fa->left = n->right;
		else
			fa->right = n->right;
	}
	else
	{
		if (n == fa->left)
			fa->left = NULL;
		else
			fa->right = NULL;
	}
}

void del(node* n) {
	if (n == NULL) return;
	if (n->left) del(n->left);
	if (n->right) del(n->right);
	delete n;
}

int main()
{
	int n, k;
	char c;
	cin >> n;
	while (n--)
	{
		cin >> c >> k;
		if (c == 'I')
		{
			if (root == NULL)
				root = new node(k);
			else
				rotate( insert(root, k) );
		}
		else if (c == 'Q')
		{
			ans = -1000000010;
			node* t = find(k);
			if (t == NULL)
				cout << ans << endl;
			else
				cout << t->key << endl;
		}
	}
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值