数据结构:Treap
关于重量平衡树的相关概念可以参考姊妹文章:重量平衡树之替罪羊树
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的更多相关文章
- [数据结构]Treap简介
[写在前面的话] 如果想学Treap,请先了解BST和BST的旋转 二叉搜索树(BST)(百度百科):[here] 英文好的读者可以戳这里(维基百科) 自己的博客:关于旋转(很水,顶多就算是了解怎么旋 ...
- 模板 - 数据结构 - Treap
还有人把Treap叫做树堆的,但是常用名还是叫做Treap的比较多. 不进行任何封装的,带求和操作的,一个节点存放多个元素的最普通的Treap. #include<bits/stdc++.h&g ...
- 【bzoj3173-最长上升子序列-一题两解】
这道题不就是简单的DP吗,BZOJ在水我!不,你是错的. ·本题特点: 不断向不同位置插入数字(按数字1,2,3,4,5,6……),需要求出每一次插入后的最长上升子序列. ·分析 ...
- [CSP-S模拟测试]:椎(线段树维护区间最值和单调栈)
题目描述 虽不能至,心向往之. $Treap=Tree+Heap$ 椎$=$树$+$堆 小$\pi$学习了计算机科学中的数据结构$Treap$. 小$\pi$知道$Treap$指的是一种树. 小$\p ...
- 数据结构之Treap
1. 概述 同splay tree一样,treap也是一个平衡二叉树,不过Treap会记录一个额外的数据,即优先级.Treap在以关键码构成二叉搜索树的同时,还按优先级来满足堆的性质.因而,Treap ...
- 模板 - 数据结构 - 可持久化无旋Treap/PersistentFHQTreap
有可能当树中有键值相同的节点时,貌似是要对Split和Merge均进行复制的,本人实测:只在Split的时候复制得到了一个WA,但只在Merge的时候复制还是AC,可能是恰好又躲过去了.有人说假如确保 ...
- 【数据结构】FHQ Treap详解
FHQ Treap是什么? FHQ Treap,又名无旋Treap,是一种不需要旋转的平衡树,是范浩强基于Treap发明的.FHQ Treap具有代码短,易理解,速度快的优点.(当然跟红黑树比一下就是 ...
- 【数据结构】【平衡树】无旋转treap
最近在研究平衡树,看起来这种东西又丧水又很深,感觉很难搞清楚.在Ditoly学长的建议下,我先学习了正常的treap,个人感觉这应该是平衡树当中比较好懂的而且比较好写的一种. 然而,发现带旋treap ...
- FHQ Treap小结(神级数据结构!)
首先说一下, 这个东西可以搞一切bst,treap,splay所能搞的东西 pre 今天心血来潮, 想搞一搞平衡树, 先百度了一下平衡树,发现正宗的平衡树写法应该是在二叉查找树的基础上加什么左左左右右 ...
- 【数据结构】【平衡树】treap
之前写treap的传送门 之前写的那个太毒瘤了,这次放一个更毒瘤的指针版上来 #include<cstdio> #include<iostream> #define rg re ...
随机推荐
- 软件工程 作业part3 读后感
匆匆看完构建之法,觉得这种不认真看完书就去写随笔去评价这本书是对作者的不尊重,所以觉得应该提问题和写感悟. 我的一点拙见,提的问题在现在这个信息发达的时候感觉只要有时间都可以自己解决. 感觉软件工程这 ...
- Spring中Controller和RequestMapping的详解
先看一个简单的实例: @Controller @RequestMapping("/hello") public class anyTypeController{ @RequestM ...
- Swift-枚举enum理解
//定义一个枚举 //枚举的语法,enum开头,每一行成员的定义使用case关键字开头,一行可以定义多个关键字 enum CompassPoint { case North case South ca ...
- python学习第二天-基本数据类型常用方法
1.直入主题 python中基本的数据类型有 数字(整形,长整形,浮点型,复数) 字符串 字节串:在介绍字符编码时介绍字节bytes类型 列表 元组 字典 集合 下面我们直接将以下面几个点进行学习 # ...
- Node js MongoDB简单操作
//win7环境下node要先安装MongoDB的相关组件(非安装MongoDB数据库),在cmd命令行进入node项目目录后执行以下语句 //npm install mongodb //创建连接 v ...
- 爬虫之手机APP抓包教程-亲测HTTP和HTTPS均可实现
当下很多网站都有做自己的APP端产品,一个优秀的爬虫工程师,必须能够绕过难爬取点而取捷径,这是皆大欢喜的.但是在网上收罗和查阅了无数文档和资料,本人亲测无数次,均不能正常获取HTTPS数据,究其原因是 ...
- Bootstrap 栅格系统初识
以下理论内容copy自bootstrap中文网(一个不错的bootstrap学习网站). 栅格系统 Bootstrap 提供了一套响应式.移动设备优先的流式栅格系统,随着屏幕或视口(viewport) ...
- bzoj1069-最大土地面积
题目 给定\(n\ (n\le 2000)\)个坐标,求四个坐标使得围起来的四边形面积最大. 分析 最暴力的想法是枚举四个点,然而肯定超时.接着不知道怎么想到中途相遇,然而一点关系都没有.这里用到了一 ...
- 【bzoj1030】[JSOI2007]文本生成器 AC自动机+dp
题目描述 JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固 ...
- BZOJ4710 JSOI2011分特产(容斥原理+组合数学)
显然可以容斥去掉每人都不为空的限制.每种物品分配方式独立,各自算一个可重组合乘起来即可. #include<iostream> #include<cstdio> #includ ...