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

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. 【转】Keepalived+Tengine实现高可用集群

    原文出处:http://502245466.blog.51cto.com/7559397/1301772 概述 近年来随着Nginx在国内的发展潮流,越来越多的互联网公司使用Nginx:凭Nginx的 ...

  2. nginx配置和网站的部署

    环境: CentOS Linux release 7.3.1611 (Core) nginx version: nginx/1.13.4 PHP 5.4.16 (cli) (built: Nov 6 ...

  3. fragment的介绍与使用

    稍稍摘录一段Fragment.java中的说明文档. /** * A Fragment is a piece of an application's user interface or behavio ...

  4. Agri-Net(最小生成树)

    Description Farmer John has been elected mayor of his town! One of his campaign promises was to brin ...

  5. Alpha发布——视频展示

    一.视频链接 http://v.youku.com/v_show/id_XMzEyODQzNzQ2MA==.html 二.视频文案说明 你是不是还在为软工作业奋笔疾书? 你是不是无法及时查看最新博客信 ...

  6. holoeverywhere修改actionbar背景

    <style name="Holo.Theme.Light.MyActionBar" parent="Holo.Base.Theme.Light.DarkActio ...

  7. Jenkins系列-Jenkins通过Publish over SSH插件实现远程部署

    配置ssh免秘钥登录 安装Publish over SSH插件 插件使用官网:https://wiki.jenkins.io/display/JENKINS/Publish+Over+SSH+Plug ...

  8. using指令含义

    using指令作用: 就是导入命名空间,这样你比如用StringBuilder类,就不用System.Text.StringBuilder builder = new System.Text.Stri ...

  9. Windows下BMP位图格式介绍

    BMP图片,是Bitmap(位图)的简称,它是windows下显示图片的基本格式.在windows下任何格式的图片文件(包括视频播放)都要转化为位图才能显示出来.各种格式的图片文件也都是在位图格式的基 ...

  10. IOUtis.copy使用解析