Treap树堆(bzoj 3224: Tyvj 1728 普通平衡树)

Treap树堆:一种排序二叉树(中序遍历权值有序)

每个节点有两个关键字:key[]和rand[]

其中key[]满足二叉搜索树性质,rand[]满足堆性质(即Tree+Heap=Treap)

如果vl是u的左孩子,则key[vl]<key[u],rand[vl]<rand[u]

如果vr是u的右孩子,则key[vr]>key[ur],rand[vr]<rand[u],但rand[vr]和rand[vl]的大小关系不确定

每次插入节点x时先按key[]值插入满足二叉搜索树的性质,插入之后,随机生成该节点rand[]值,之后按rand[]值大小调整树的结构(翻转),以满足堆性质,期望树高(logn)

每次删除时将要删除的节点翻转到叶子然后删除(或者翻转到它只有一个儿子的情况)

翻转规则如下:


没了


3224: Tyvj 1728 普通平衡树

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 14281   Solved: 6197
[ Submit][ Status][ Discuss]

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每行输出一个数,表示对应答案

Sample Input

10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

Sample Output

106465
84185
492737

#include<stdio.h>
#include<stdlib.h>
using namespace std;
typedef struct
{
	int l, r;
	int val, rnd;
	int size, sum;
}Tree;
Tree tre[100005];
int n, id, root, ans;
void Update(int k)
{
	tre[k].size = tre[tre[k].l].size+tre[tre[k].r].size+tre[k].sum;
}
void Rtroot(int &k)
{
	int t;
	t = tre[k].l;
	tre[k].l = tre[t].r;
	tre[t].r = k;
	tre[t].size = tre[k].size;
	Update(k);
	k = t;
}
void Ltroot(int &k)
{
	int t;
	t = tre[k].r;
	tre[k].r = tre[t].l;
	tre[t].l = k;
	tre[t].size = tre[k].size;
	Update(k);
	k = t;
}
void Insert(int &k, int x)
{
	if(k==0)
	{
		k = ++id;
		tre[k].size = tre[k].sum = 1;
		tre[k].val = x;
		tre[k].rnd = rand();
		return;
	}
	tre[k].size++;
    if(tre[k].val==x)
		tre[k].sum++;				//如果要插入的权值在树中已有节点,直接更新数量
	else if(x>tre[k].val)
	{
		Insert(tre[k].r, x);
		if(tre[tre[k].r].rnd<tre[k].rnd)
			Ltroot(k);					//维护堆性质
	}
	else
	{
		Insert(tre[k].l, x);
		if(tre[tre[k].l].rnd<tre[k].rnd)
			Rtroot(k);
	}
}
void Delete(int &k, int x)
{
    if(k==0)
		return;
	if(tre[k].val==x)
	{
		if(tre[k].sum>1)
		{
			tre[k].sum--;
			tre[k].size--;
			return;
		}
				//↓删除节点k
		if(tre[k].l*tre[k].r==0)
			k = tre[k].l+tre[k].r;
		else if(tre[tre[k].l].rnd<tre[tre[k].r].rnd)	//将k点通过翻转往叶子方向移动,左旋还是右旋看哪种满足堆性质
		{
			Rtroot(k);
			Delete(k, x);
		}
		else
		{
			Ltroot(k);
			Delete(k, x);
		}
	}
	else if(x>tre[k].val)
	{
		tre[k].size--;
		Delete(tre[k].r, x);
	}
	else
	{
		tre[k].size--;
		Delete(tre[k].l, x);
	}
}
int Query_rank(int k, int x)
{
    if(k==0)
		return 0;
	if(tre[k].val==x)
		return tre[tre[k].l].size+1;
	else if(x>tre[k].val)
		return tre[tre[k].l].size+tre[k].sum+Query_rank(tre[k].r,x);
	else
		return Query_rank(tre[k].l, x);
}
int Query_num(int k, int x)
{
    if(k==0)
		return 0;
	if(x<=tre[tre[k].l].size)
		return Query_num(tre[k].l, x);
    else if(x>tre[tre[k].l].size+tre[k].sum)
		return Query_num(tre[k].r, x-tre[tre[k].l].size-tre[k].sum);
    else
		return tre[k].val;
}
void Query_pro(int k, int x)
{
    if(k==0)
		return;
    if(tre[k].val<x)
	{
		ans = k;
		Query_pro(tre[k].r, x);
	}
    else
		Query_pro(tre[k].l, x);
}
void Query_sub(int k, int x)
{
	if(k==0)
		return;
	if(tre[k].val>x)
	{
		ans = k;
		Query_sub(tre[k].l, x);
	}
	else
		Query_sub(tre[k].r, x);
}
int main(void)
{
	int t, x, i;
	scanf("%d", &n);
	id = root = 0;
	for(i=1;i<=n;i++)
	{
		scanf("%d%d", &t, &x);
		switch(t)
		{
			case 1:  Insert(root, x);  break;
			case 2:  Delete(root, x);  break;
			case 3:  printf("%d\n", Query_rank(root, x));  break;
			case 4:  printf("%d\n", Query_num(root, x));  break;
			case 5:  ans=0;  Query_pro(root, x);  printf("%d\n", tre[ans].val);  break;
			case 6:  ans=0;  Query_sub(root, x);  printf("%d\n", tre[ans].val);  break;
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值