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;
}