您的位置:首页 > 其它

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

2017-07-20 13:08 417 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: