关于重量平衡树的相关概念可以参考姊妹文章:重量平衡树之替罪羊树

Treap是依靠旋转来维护平衡的重量平衡树中最为好写的一中,因为它的旋转不是LL就是RR

对于每一个新的节点,它给这个节点分配了一个随机数,用作优先级,然后以这个优先级来维护一个堆结构

由于堆本身就是完全二叉树结构,这样维护之后的树就无限接近于完全二叉树,所以还是很神奇的

这棵树满足BST的一切性质,除了不能处理序列问题之外已经无敌了

应该说,抛去动态树问题之外,这是实战最好用的树了

我们还是先看定义:

struct Tree
{
int v,w;
int size;
int rnd;
int ch[];
}t[maxn];
int root;
int size;
int ans=;

在这里v是值,w是同值的节点个数,size是子树的节点总数,rnd是优先级,外面:root是根节点,size是根节点中元素个数,ans是统计答案用的临时变量

我们这里还是先介绍插入操作,平衡树问题如果不是处理序列的,建议就一个一个插

void insert(int &k,int x)
{
if(k==)
{
size++;
k=size;
t[k].size=t[k].w=;
t[k].v=x;
t[k].rnd=rand();
return;
}
t[k].size++;
if(t[k].v==x)
t[k].w++;
else if(x>t[k].v)
{
insert(t[k].ch[],x);
if(t[t[k].ch[]].rnd<t[k].rnd)
lturn(k);
}
else
{
insert(t[k].ch[],x);
if(t[t[k].ch[]].rnd<t[k].rnd)
rturn(k);
}
}

插入时根据是否是叶子节点,遍历到的节点的w值等进行维护

每次插入要判断一下是否满足堆结构,进行相应的旋转调整

下面给出旋转调整的函数,基本上可以作为左旋和右旋的模板了

void rturn(int &k)
{
int tmp=t[k].ch[];
t[k].ch[]=t[tmp].ch[];
t[tmp].ch[]=k;
t[tmp].size=t[k].size;
update(k);
k=tmp;
}
void lturn(int &k)
{
int tmp=t[k].ch[];
t[k].ch[]=t[tmp].ch[];
t[tmp].ch[]=k;
t[tmp].size=t[k].size;
update(k);
k=tmp;
}

然后我们给出update函数,这里要维护的东西很少,只有一个size,所以这个时候的update就是更新size用的

void update(int k)
{
t[k].size=t[t[k].ch[]].size+t[t[k].ch[]].size+t[k].w;
}

然后是四种基本查询工作,各种平衡树基本一致,也可以作为模板记下来了

int query_rank(int k,int x)
{
if(k==)
return ;
if(t[k].v==x)
return t[t[k].ch[]].size+;
else if(x>t[k].v)
return t[t[k].ch[]].size+t[k].w+query_rank(t[k].ch[],x);
else
return query_rank(t[k].ch[],x);
}
int query_num(int k,int x)
{
if(k==)
return ;
if(x<=t[t[k].ch[]].size)
return query_num(t[k].ch[],x);
else if(x>t[t[k].ch[]].size+t[k].w)
return query_num(t[k].ch[],x-t[t[k].ch[]].size-t[k].w);
else
return t[k].v;
}
void query_pro(int k,int x)
{
if(k==)
return;
if(t[k].v<x)
ans=k,query_pro(t[k].ch[],x);
else
query_pro(t[k].ch[],x);
}
void query_sub(int k,int x)
{
if(k==)
return;
if(t[k].v>x)
ans=k,query_sub(t[k].ch[],x);
else
query_sub(t[k].ch[],x);
}

最后我们给出完整的模板,这棵树一定要熟练掌握,只要是平衡树问题,很大可能都是用它来完成的

 #include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=;
int n;
struct Tree
{
int v,w;
int size;
int rnd;
int ch[];
}t[maxn];
int root;
int size;
int ans=;
void update(int k)
{
t[k].size=t[t[k].ch[]].size+t[t[k].ch[]].size+t[k].w;
}
void rturn(int &k)
{
int tmp=t[k].ch[];
t[k].ch[]=t[tmp].ch[];
t[tmp].ch[]=k;
t[tmp].size=t[k].size;
update(k);
k=tmp;
}
void lturn(int &k)
{
int tmp=t[k].ch[];
t[k].ch[]=t[tmp].ch[];
t[tmp].ch[]=k;
t[tmp].size=t[k].size;
update(k);
k=tmp;
}
void insert(int &k,int x)
{
if(k==)
{
size++;
k=size;
t[k].size=t[k].w=;
t[k].v=x;
t[k].rnd=rand();
return;
}
t[k].size++;
if(t[k].v==x)
t[k].w++;
else if(x>t[k].v)
{
insert(t[k].ch[],x);
if(t[t[k].ch[]].rnd<t[k].rnd)
lturn(k);
}
else
{
insert(t[k].ch[],x);
if(t[t[k].ch[]].rnd<t[k].rnd)
rturn(k);
}
}
void del(int &k,int x)
{
if(k==)
return;
if(t[k].v==x)
{
if(t[k].w>)
{
t[k].w--;
t[k].size--;
return;
}
if(t[k].ch[]*t[k].ch[]==)
k=t[k].ch[]+t[k].ch[];
else if(t[t[k].ch[]].rnd<t[t[k].ch[]].rnd)
rturn(k),del(k,x);
else
lturn(k),del(k,x);
}
else if(x>t[k].v)
t[k].size--,del(t[k].ch[],x);
else
t[k].size--,del(t[k].ch[],x);
}
int query_rank(int k,int x)
{
if(k==)
return ;
if(t[k].v==x)
return t[t[k].ch[]].size+;
else if(x>t[k].v)
return t[t[k].ch[]].size+t[k].w+query_rank(t[k].ch[],x);
else
return query_rank(t[k].ch[],x);
}
int query_num(int k,int x)
{
if(k==)
return ;
if(x<=t[t[k].ch[]].size)
return query_num(t[k].ch[],x);
else if(x>t[t[k].ch[]].size+t[k].w)
return query_num(t[k].ch[],x-t[t[k].ch[]].size-t[k].w);
else
return t[k].v;
}
void query_pro(int k,int x)
{
if(k==)
return;
if(t[k].v<x)
ans=k,query_pro(t[k].ch[],x);
else
query_pro(t[k].ch[],x);
}
void query_sub(int k,int x)
{
if(k==)
return;
if(t[k].v>x)
ans=k,query_sub(t[k].ch[],x);
else
query_sub(t[k].ch[],x);
}
int main()
{
cin>>n;
int tmp,x;
for(int i=;i<=n;i++)
{
cin>>tmp>>x;
switch(tmp)
{
case :insert(root,x);break;
case :del(root,x);break;
case :cout<<query_rank(root,x)<<endl;break;
case :cout<<query_num(root,x)<<endl;break;
case :ans=;query_pro(root,x);cout<<t[ans].v<<endl;break;
case :ans=;query_sub(root,x);cout<<t[ans].v<<endl;break;
}
}
return ;
}

数据结构:Treap的更多相关文章

  1. [数据结构]Treap简介

    [写在前面的话] 如果想学Treap,请先了解BST和BST的旋转 二叉搜索树(BST)(百度百科):[here] 英文好的读者可以戳这里(维基百科) 自己的博客:关于旋转(很水,顶多就算是了解怎么旋 ...

  2. 模板 - 数据结构 - Treap

    还有人把Treap叫做树堆的,但是常用名还是叫做Treap的比较多. 不进行任何封装的,带求和操作的,一个节点存放多个元素的最普通的Treap. #include<bits/stdc++.h&g ...

  3. 【bzoj3173-最长上升子序列-一题两解】

    这道题不就是简单的DP吗,BZOJ在水我!不,你是错的. ·本题特点:       不断向不同位置插入数字(按数字1,2,3,4,5,6……),需要求出每一次插入后的最长上升子序列. ·分析      ...

  4. [CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)

    题目描述 虽不能至,心向往之. $Treap=Tree+Heap$ 椎$=$树$+$堆 小$\pi$学习了计算机科学中的数据结构$Treap$. 小$\pi$知道$Treap$指的是一种树. 小$\p ...

  5. 数据结构之Treap

    1. 概述 同splay tree一样,treap也是一个平衡二叉树,不过Treap会记录一个额外的数据,即优先级.Treap在以关键码构成二叉搜索树的同时,还按优先级来满足堆的性质.因而,Treap ...

  6. 模板 - 数据结构 - 可持久化无旋Treap/PersistentFHQTreap

    有可能当树中有键值相同的节点时,貌似是要对Split和Merge均进行复制的,本人实测:只在Split的时候复制得到了一个WA,但只在Merge的时候复制还是AC,可能是恰好又躲过去了.有人说假如确保 ...

  7. 【数据结构】FHQ Treap详解

    FHQ Treap是什么? FHQ Treap,又名无旋Treap,是一种不需要旋转的平衡树,是范浩强基于Treap发明的.FHQ Treap具有代码短,易理解,速度快的优点.(当然跟红黑树比一下就是 ...

  8. 【数据结构】【平衡树】无旋转treap

    最近在研究平衡树,看起来这种东西又丧水又很深,感觉很难搞清楚.在Ditoly学长的建议下,我先学习了正常的treap,个人感觉这应该是平衡树当中比较好懂的而且比较好写的一种. 然而,发现带旋treap ...

  9. FHQ Treap小结(神级数据结构!)

    首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...

  10. 【数据结构】【平衡树】treap

    之前写treap的传送门 之前写的那个太毒瘤了,这次放一个更毒瘤的指针版上来 #include<cstdio> #include<iostream> #define rg re ...

随机推荐

  1. HDU 1250 Hat's Fibonacci(高精度)

    Problem Description A Fibonacci sequence is calculated by adding the previous two members the sequen ...

  2. Python中的Comprehensions和Generations

    Python中的Comprehensions和Generations语法都是用来迭代的.Comprehensions语法可用于list,set,dictionary上,而Generations语法分为 ...

  3. 如何遍历一个文件夹(C语言实现)

    #include<io.h> #include<stdio.h> int main() { long Handle; struct _finddata_t FileInfo; ...

  4. 深入理解Java之数据类型

    一.概述 我们通过编程解决一个具体问题时,首先要做的工作是用各种“数据结构”表示问题中的实体对象,而后才能着手研究描述具体业务逻辑的算法.这也正印证了”程序 = 数据结构 + 算法“.而这里的数据结构 ...

  5. LintCode-373.奇偶分割数组

    奇偶分割数组 分割一个整数数组,使得奇数在前偶数在后. 样例 给定 [1, 2, 3, 4],返回 [1, 3, 2, 4]. 挑战 在原数组中完成,不使用额外空间. 标签 数组 两根指针 code ...

  6. 第50天:scrollTo小火箭返回顶部

    scrollTo(x,y)//可把内容滚动到指定的坐标scrollTo(xpos,ypos)//x,y值必需 1.固定导航栏 <!DOCTYPE html> <html lang=& ...

  7. 按照list中实体类的某一属性排序

    传进一个装有实体类的list public void sort(List<MedicalPracticesDetail> mpdList){ Collections.sort(mpdLis ...

  8. Python 嵌套函数和闭包

    Python 嵌套函数和闭包 1.函数嵌套 如果在一个函数内部定义了另一个函数,我们称外部的函数为外函数,内部的函数为内函数,如下代码: def out_func(): def inner_func1 ...

  9. VS2017常用快快捷键

    VS2017常用快快捷键 VS中代码对齐等快捷键        在VS中,选定代码后,按Ctrl+K+F组合键,可以自动进行代码对齐.        注意:要先按下Ctrl和K,再按下F,因为Ctrl ...

  10. POJ3977:Subset——题解(三分+折半搜索)

    http://poj.org/problem?id=3977 题目大意:有一堆数,取出一些数,记他们和的绝对值为w,取的个数为n,求在w最小的情况下,n最小,并输出w,n. ————————————— ...