真·浅谈treap树
treap树是一种平衡树,它有平衡树的性质,满足堆的性质,是二叉搜索树,但是我们需要维护他
为什么满足堆的性质?因为每个节点还有一个随机权值,按照随机权值维持这个堆(树),可以用O(logn)的复杂度维护他。树的期望深度是log n。
平衡树是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。权值:右儿子大于爸爸大于左儿子。
那么如何维护他呢?
我们来看看维护treap树的几个操作。
1.左旋右旋:
旋转是什么?看图:

把父亲和他左(右)儿子及其各子树调换(反了!)
左旋:左儿子上窜(爸爸的左儿子换成儿子的右儿子,儿子的右儿子换成爸爸)
右旋:右儿子上窜(爸爸的右儿子换成儿子的左儿子,儿子的左儿子换成爸爸)
左旋右旋看上去没有用,但是他是服务于插入和删除操作的。
代码:
void update(int cur){
sz[cur] = sz[lc[cur]] + sz[rc[cur]] + ;
}
void right_rotate(int &Q){
int P = lc[Q];
lc[Q] = rc[P];
rc[P] = Q; //爸爸的左儿子换成儿子的右儿子,儿子的右儿子换成爸爸
update(Q); //更新右子树大小
update(P); //更新左子树大小
Q = P; //把Q换成P
}
void left_rotate(int &Q){
int P = rc[Q];
rc[Q] = lc[P];
lc[P] = Q;
update(Q);
update(P);
Q = P;
}
2.插入
插入就需要左旋右旋了,因为我们既维持treap其平衡树的性质,也要维持他堆的性质。
void insert(int &cur, int v){
if(!cur)
{
cur = ++cnt; //新加点的编号
V[cnt] = v; //把权值赋给它
R[cnt] = rand(); //给出点的随机权值
return;
}
if(v < V[cur]) //比较新加点与当前点的权值
{
insert(lc[cur], v); //把当前点放到他左儿子身上,递归下去
update(cur); //更新子树大小
if(R[lc[cur]] < R[cur]) //保持堆的性质
right_rotate(cur);
}
else
{
insert(rc[cur], v); //把当前点放到他左儿子身上,递归下去
update(cur); //更新子树大小
if(R[rc[cur]] < R[cur]) //保持堆的性质
left_rotate(cur);
}
}
3.删除
void del(int &cur, int v){//cur当前节点,v表示要删的点的权值
if(!cur)
return;
if(V[cur] == v)
{
if(lc[cur] && rc[cur])
{
left_rotate(cur);
del(lc[cur], v);
}
else
{
cur = lc[cur] | rc[cur];
update(cur);
return;
}
}
else if(V[cur] > v)
del(lc[cur], v);
else
del(rc[cur], v);
update(cur);
}
4.第k大,前驱,后继
这些都是递归求的。
比如前驱,如果当前点的权值小于要找的值,那么走它的右子树,直到当前点权值大于要找的值,找它的左子树,因为左子树比当前点权值小。
int find(int cur, int v)
{
if(V[cur] == v)
return ;
else if(V[cur] > v)
return find(lc[cur], v);
else
return sz[lc[cur]] + + find(rc[cur], v);
}
int pre(int cur,int v)
{
if(!cur)
return 0xefefefef;
if(v < V[cur])
return pre(lc[cur],v);
return max(V[cur],pre(rc[cur],v)); }
int post(int cur,int v)
{
if(!cur)
return 0x7fffffff;
if(v > V[cur])
return post(rc[cur],v);
return min(V[cur],post(lc[cur],v));
}
差不多就是这些……
洛谷板题:https://www.luogu.org/problemnew/show/P3369
真·浅谈treap树的更多相关文章
- 浅谈B+树索引的分裂优化(转)
http://www.tamabc.com/article/85038.html 从MySQL Bug#67718浅谈B+树索引的分裂优化 原文链接:http://hedengcheng.com/ ...
- 浅谈oracle树状结构层级查询之start with ....connect by prior、level及order by
浅谈oracle树状结构层级查询 oracle树状结构查询即层次递归查询,是sql语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只 ...
- 浅谈oracle树状结构层级查询测试数据
浅谈oracle树状结构层级查询 oracle树状结构查询即层次递归查询,是sql语句经常用到的,在实际开发中组织结构实现及其层次化实现功能也是经常遇到的,虽然我是一个java程序开发者,我一直觉得只 ...
- (转)浅谈trie树
浅谈Trie树(字典树) Trie树(字典树) 一.引入 字典是干啥的?查找字的. 字典树自然也是起查找作用的.查找的是啥?单词. 看以下几个题: 1.给出n个单词和m个询问,每次询问 ...
- 浅谈Huffman树
所谓Huffman树,就是叶子结点带权的\(K\)叉树,假设每个叶子的权值为\(v\),到根的距离为\(dep\),那么最小化\(\sum v_i*dep_i\)就是\(Huffman\)树的拿手好戏 ...
- 【转】Senior Data Structure · 浅谈线段树(Segment Tree)
本文章转自洛谷 原作者: _皎月半洒花 一.简介线段树 ps: _此处以询问区间和为例.实际上线段树可以处理很多符合结合律的操作.(比如说加法,a[1]+a[2]+a[3]+a[4]=(a[1]+a[ ...
- 浅谈B树
B树即二叉搜索树: 1.所有非叶子结点至多拥有两个儿子(Left和Right): 2.所有结点存储一个关键字: 3.非叶子结点的左指针指向小于其关键字的子树,右指针指向大于其关键字的子树: 如: ...
- 浅谈 trie树 及其实现
定义:又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构, 如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树. 核心思想:是空间换时间.利用字符串的公共前缀来降低查询时间的开 ...
- 浅谈Trie树(字典树)
Trie树(字典树) 一.引入 字典是干啥的?查找字的. 字典树自然也是起查找作用的.查找的是啥?单词. 看以下几个题: 1.给出n个单词和m个询问,每次询问一个单词,回答这个单词是否在单 ...
随机推荐
- 【译】Building ArduPilot on Windows with waf and Bash
原文链接:http://ardupilot.org/dev/docs/building-ardupilot-onwindows10.html 翻译水平有限,如有错误请指出! 在Windows上使用wa ...
- SpringBoot配置(2) slf4j&logback
SpringBoot配置(2) slf4j&logback 一.SpringBoot的日志使用 全局常规设置(格式.路径.级别) SpringBoot能自动适配所有的日志,而且底层使用slf4 ...
- 学习笔记之scikit-learn
scikit-learn: machine learning in Python — scikit-learn 0.20.0 documentation https://scikit-learn.or ...
- MySQL之Haproxy+Keepalived+MySQL高可用均衡负载部署 (网络摘抄)
来源于:https://blog.csdn.net/weisong530624687/article/details/71536837?utm_source=blogxgwz3 一.安装主从MySQL ...
- 关于CoreData的用法
有些同事觉得CoreData是一个看不懂,理解不清的神秘东东,其实ios的本地数据储存是一个sqlite数据库,一个简易的数据库,而这个CoreData是否支持所有储存的数据呢,显然不是的,站在我的角 ...
- Python直接改变实例化对象的列表属性的值 导致在flask中接口多次请求报错
错误原理实例如下: class One(): list = [1, 2, 3] @classmethod def get_copy_list(cls): # copy一份list,这样对list的改变 ...
- Mac 日常使用tips
20180725: windows标准的键盘连接了mac如何映射键盘?最大的好处是可以向后删除,还可以一键PageUP, PageDown ref: https://support.apple.com ...
- linux 时间和时区设置
在linux中与时间相关的文件有 /etc/localtime /etc/timezone 其中,/etc/localtime是用来描述本机时间,而 /etc/timezone是用来描述本机所属的时区 ...
- python3 互译无线短信接口
#!/usr/local/bin/python#-*- coding:utf-8 -*-import http.clientimport urllibimport random host = &quo ...
- JRebel 代理激活
1.生成GUID https://www.guidgen.com/ 例:04cfff79-8f45-481c-a858-a5b9590422e7 2.License Server 例: http: ...