Treap 实现名次树
在主流STL版本中,set,map,都是BST实现的,具体来说是一种称为红黑树的动态平衡BST;
但是在竞赛中并不常用,因为红黑树过于复杂,他的插入 5 种,删除 6 中,代码量极大(如果你要改板子的话);
相比之下有一种Treap的动态平衡BST,却也可以做到插入,删除,查找的期望时间复杂度O(logn);
结点定义:
struct Node {
Node *ch[];
int r; //优先级
int v; //值
int s; //结点总数 Node(int v):v(v) {
ch[] = ch[] = NULL;
r = rand();
s = ;
} bool operator < (const Node& rhs) const {
return r < rhs.r;
} int cmp(int x) const {
if(x==v) return -;
return x < v ? :;
} void maintain() {
s = ;
if(ch[]!=NULL) s +=ch[]->s;
if(ch[]!=NULL) s +=ch[]->s;
}
};
我这里加了一些看似不需要的东西s,而这个 s却是Treap相比BST的闪光点!!!
动态平衡二叉树 BST 的性质 v,值,根大于左子树,小于右子树; cmp函数,插入,删除时,小于 v,返回 0;
r : 堆的性质,大根堆,根优先级最高;
旋转操作是一个坎,虽然不难,但是好多书籍上面感觉欲言又止;
左旋: 由于 堆的性质,可能使得 BST 不对(插入,删除),需要旋转,比如说,o点的优先级小于 k 点的优先级,要左旋,(大于,相反)
这个时候要是还想满足BST的性质,只需要改动几个点,就ok了。
//旋转
void rotate(Node* &o,int d) {
Node* k = o->ch[d^];
o->ch[d^] = k->ch[d];
k->ch[d] = o;
o->maintain();
k->maintain();
o = k;
}
同时,maintain函数,要重新统计节点数。
插入操作;
首先按照普通的BST递归插入;
插入后,发现,此时的堆性质已经不满足了;要进行递归旋转!!!
//插入
void insert(Node* &o,int x) {
if(o==NULL) o = new Node(x);
else {
int d = (x< o->v?:); //可能有相同的元素要插入
insert(o->ch[d],x);
if(o->ch[d]->r > o->r)
rotate(o,d^);
}
o->maintain();
}
同样,每次递归到一层,重新维护节点信息;
删除操作:
首先递归找到这个结点;
这个结点如果左子树为空,或者右子树为空,很好解决;相反的子树代替父节点;
要是两者都有怎么解决?保持堆的性质 和 BST的性质?
先不急于删去点,首先比较一下左右子树的优先级,把优先级较高的子树旋转到根;
例如上图中,加入 k 较高,右旋到左边的图;然后递归删除 k ,这样就保证了整个Treap树的性质!!!
//删除
void remove(Node* &o,int x) {
int d = o->cmp(x);
if(d==-) {
Node* u = o;
if(o->ch[]!=NULL&&o->ch[]!=NULL) {
int d2 = (o->ch[]->r > o->ch[]->r ? : );
rotate(o,d2);
remove(o->ch[d2],x);
}
else {
if(o->ch[]==NULL)
o = o ->ch[];
else o = o ->ch[];
}
}
else {
remove(o->ch[d],x);
}
if(o!=NULL) o->maintain();
}
注意:插入,删除,的时候没有去检查,可以先去检查了一下,这样就完全和set是一样的了
int find(Node* o,int x) {
while(o!=NULL) {
int d = o->cmp(x);
if(d==-) return ; //存在
else o = o->ch[d];
}
return ; //不存在
}
到了这里就已经完全实现了Treap树了,很happy\(^o^)/~
但是:
如果说,Treap树和 set 是一样的,那就没必要写 Treap了,举个栗子!
名次树!!!
个人柑橘往左子树走很巧妙, (^-^)V
利用右子树有多少节点而往左子树走;
//名次树
Node* root[maxn]; //第 k 大的值
int kth(Node* o,int k) {
if(o==NULL||k<=||k>o->s) return ;
int s = (o->ch[]==NULL ? : o->ch[]->s);
if(k==s+) return o->v;
else if(k<=s) return kth(o->ch[],k);
else return kth(o->ch[],k-s-);
}
Treap 实现名次树的更多相关文章
- Treap和名次树
Treap名字的来源:Tree+Heap,正如名字一样,就是一颗简单的BST,一坨堆的合体.BST的不平衡的根本原因在于基于左<=根<=右的模式吃单调序列时候会无脑成长链,而Treap则添 ...
- 模板——Treap实现名次树
Treap 是一种通过赋予结点随机权值的一种满足堆性质的二叉搜索树,它很好的解决了二叉搜索树顺序插入组成链式的局限性. 名次树是指在treap的每个结点中添加附加域size,表示以它为根的子树的总结点 ...
- 「模板」「讲解」Treap名次树
Treap实现名次树 前言 学平衡树的过程可以说是相当艰难.浏览Blog的过程中看到大量指针版平衡树,不擅长指针操作的我已经接近崩溃.于是,我想着一定要写一篇非指针实现的Treap的Blog. 具体如 ...
- bzoj3224 Tyvj 1728 普通平衡树(名次树+处理相同)
3224: Tyvj 1728 普通平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 5354 Solved: 2196[Submit][Sta ...
- uvalive 5031 Graph and Queries 名次树+Treap
题意:给你个点m条边的无向图,每个节点都有一个整数权值.你的任务是执行一系列操作.操作分为3种... 思路:本题一点要逆向来做,正向每次如果删边,复杂度太高.逆向到一定顺序的时候添加一条边更容易.详见 ...
- UVa 1479 (Treap 名次树) Graph and Queries
这题写起来真累.. 名次树就是多了一个附加信息记录以该节点为根的树的总结点的个数,由于BST的性质再根据这个附加信息,我们可以很容易找到这棵树中第k大的值是多少. 所以在这道题中用一棵名次树来维护一个 ...
- LA 5031 Graph and Queries —— Treap名次树
离线做法,逆序执行操作,那么原本的删除边的操作变为加入边的操作,用名次树维护每一个连通分量的名次,加边操作即是连通分量合并操作,每次将结点数小的子树向结点数大的子树合并,那么单次合并复杂度O(n1lo ...
- bzoj 3196 Tyvj 1730 二逼平衡树(线段树套名次树)
3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1807 Solved: 772[Submit][Stat ...
- UVaLive5031 Graph and Queries(时光倒流+名次树)
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20332 [思路] 时光倒流+名次树(rank tree). 所谓“ ...
随机推荐
- Java学习笔记day07_琐碎知识_水仙花数_ASCII码_冒泡排序_简单选择排序_折半查找
琐碎知识: 水仙花数, ASCII码, 冒泡排序, 简单选择排序, 折半查找 1.水仙花数 每位数的平方的和等于本身. 如100到999之间的水仙花数满足: 个位的平方+十位的平方+百位的平方 = 本 ...
- thinkPHP5.0验证码不显示
1.使用composer安装时,验证码无法正常显示 主要是因为验证码扩展库的版本安装不正常,官方的5.0版本的扩展库版本号都是1.*,默认安装的是2.0版本,2.0版本均为ThinkPHP5.1版本专 ...
- 学习 emplace_back() 和 push_back 的区别 emplace_back效率高
在引入右值引用,转移构造函数,转移复制运算符之前,通常使用push_back()向容器中加入一个右值元素(临时对象)的时候,首先会调用构造函数构造这个临时对象,然后需要调用拷贝构造函数将这个临时对象放 ...
- Android官方架构组件介绍之LifeCycle(一)
Android官方架构组件介绍之LifeCycle 下面是官方提供的Android App开发的架构图: 从上图可以看到一些关键字:ViewModel,LiveData,Room等.其实看了上面视频的 ...
- red5服务器基础之red5环境的安装配置
red5的官网地址http://red5.org/ 下载完成之后解压 在系统变量配置RED5_HOME 在浏览器里输入 http://localhost:5080/ 配置ip地址在安装目录D:\red ...
- 2019.03.22 读书笔记 var object dynamic
var:语法糖,在编译时推断出类型,根据反编译可以看出.实际用处是增加代码的健壮性,比如 linq ,匿名对象等. object:很多人容易和var混淆,其实概念上完全不同,没什么可比性. dynam ...
- jQuery中的事件和动画 以及视频展示效果实例
经过这几天学习jQuery中的事件和动画,对jQuery更深的认识,接下来先把视频展示效果的代码贴出来,最后把我在学习jQuery事件和动画之后总结的思维导图 <!doctype html> ...
- pat03-树1. 二分法求多项式单根(20)
03-树1. 二分法求多项式单根(20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 杨起帆(浙江大学城市学院) 二分法求函数根的 ...
- httpd 的坑
Httpd服务器的坑 在/etc/httpd/conf/httpd.conf中的配置信息, 有时注释到的内容仍然会生效 配置Auth时, 允许htpasswd规定的文件中的所有的用户, Require ...
- python面试题——爬虫相关
1.接触过几种爬虫模块 urllib.requests这两种爬虫模块. 2.robots协议是什么? 它就是一个防君子不防小人的协议,网站有一些数据不想被爬虫程序爬取,可以编写robots协议文件,明 ...