[note]fhq_treap
fhq_treap
这东西据说是某个叫范浩强的神仙搞出来的,
他的这种treap可以不用旋转并且资磁很多平衡树操作,
复杂度通过随机的键值来保证(树大致平衡,期望一次操作复杂度\(logn\))
依靠核心函数split和merge实现绝大多数操作
首先建树的话可以笛卡尔树优化到\(O(n)\),暴力merge\(O(nlogn)\)
通过以下几个操作进行说明(以下默认权值与v相同split到左边)
- 插入数v:将原树从v的位置分裂成x,y,合并x,v,再合并x,y.
- 删除数v:将原树从v-1分裂成x,y,将y从v分成y,z,那么将y树的根删去(\(merge(ls_y,rs_y)\))
(ps:如果相同权值的全删掉,那么整个y树都不要了),接着把剩下x,y,z的merge回来. - 查询v的rank(rank定义为比v小的数的个数+1):那么从v-1处split成x,y,返回x树的sz+1.
- 查询rank为k的数:同普通treap,不详述.
- 查询v的前驱:从v-1处split成x,y,返回x树的最后一个,为空则无.(ps:查询第sz个用求k大的方法)
- 查询v的前驱:从v处split成x,y,返回y树的第一个,为空则无.
split
上述操作的split均按权值分裂,我们先来看看split函数
[按权值split]
void split(int x,int&l,int&r,int k){
if(!x){l=r=0;return;}//到空节点返回0
if(val[x]<=k){l=x;split(rs[l],rs[l],r,k);pu(l);}//x分给左树,接着分x的右儿子
else{r=x;split(ls[r],l,ls[r],k);pu(r);}//x分给右树,接着分x的左儿子
}
[按下标split]
void split(int x,int&l,int&r,int k){
if(!x){l=r=0;return;}
if(sz[ls[x]]+1<=k){l=x;split(rs[l],rs[l],r,k-sz[ls[x]]-1);pu(l);}//注意修改k
else{r=x;split(ls[r],l,ls[r],k);pu(r);}
}
对于我们遍历到每一个点,假如它的权值小于等于k,那么它的所有左子树,都要分到左边的树里,然后遍历它的右儿子.
假如大于k,把它的所有右子树分到右边的树里,遍历左儿子.
merge
再看merge函数(默认满足大根堆性质)
void merge(int&x,int l,int r){
if(!l||!r){x=l|r;return;}//l或r为空则返回另一个
if(fix[l]>fix[r]){x=l;merge(rs[x],rs[x],r);}//按键值确定父子关系
else{x=r;merge(ls[x],l,ls[x]);}pu(x);
}
由于第一棵树的权值都小于第二棵树,那么就只需要比较键值确定父子关系
如果fix[l]>fix[r],那么比较l的右儿子和r
否则比较r的左儿子和l,递归merge
以上是一些基本操作,有了这些可以完成[模板]普通平衡树
放几个函数的code
void insert(int v){
int x,y;split(rt,x,y,v-1);
merge(x,x,newnode(v));merge(rt,x,y);
}
void del(int v){
int x,y,z;split(rt,x,y,v);split(x,x,z,v-1);
merge(z,ls[z],rs[z]);merge(x,x,z);merge(rt,x,y);
}
void rk(int v){
int x,y;split(rt,x,y,v-1);
printf("%d\n",sz[x]+1);merge(rt,x,y);
}
int kth(int k){
int x=rt;
while(1){
if(k==sz[ls[x]]+1)return val[x];
if(k<=sz[ls[x]])x=ls[x];
else k-=sz[ls[x]]+1,x=rs[x];//注意先修改k!!!
}
}
void pre(int v){
int x,y;split(rt,x,y,v-1);
printf("%d\n",sz[x]?kth(x,sz[x]):-inf);
merge(rt,x,y);
}
void suf(int v){
int x,y;split(rt,x,y,v);
printf("%d\n",sz[y]?kth(y,1):inf);
merge(rt,x,y);
}
有的时候我们需要对一个区间进行操作,这时只要
void XXX(int l,int r){
int x,y,z;split(rt,x,y,r);split(x,x,z,l-1);
//do sth such as put reverse tag,put add tag
merge(x,x,z);merge(rt,x,y);
}
可持久化
说起来目前为止这都是很多平衡树都能维护的东西,
而且我们发现每次操作都需要split和merge多次,这会是一个较大的常数
那么它牛逼在哪里?
它容易写
它可以持久化.
我们只需要将原先的根rt开成rt[],每次访问v版本就在rt[v]上查,
我们知道可持久化对修改有一个要求就是修改不能影响之前的版本,也就是不能改变先前版本的树的形态
我们发现涉及形态修改的函数只有merge和split,于是我们稍作修改
[可持久化split]
void split(int x,int&l,int&r,int k){
if(!x){l=r=0;return;}
if(k>=val[x]){l=++tot;cp(l,x);split(rs[l],rs[l],r,k);pu(l);}//cp即copy,把节点复制过来
else{r=++tot;cp(r,x);split(ls[r],l,ls[r],k);pu(r);}
}
[可持久化merge]
void merge(int&x,int l,int r){
if(!l||!r){x=l|r;return;}x=++tot;//新建节点
if(fix[l]>fix[r]){cp(x,l);merge(rs[x],rs[x],r);}
else{cp(x,r);merge(ls[x],l,ls[x]);}pu(x);
}
讨论中有提到merge不用再开点,因为点已经在split中建好了
对此博主并不太清楚,欢迎大佬指教
我们发现空间是\(nlogn\)(n是修改操作数)的,由于一次操作需要多次split,merge所以空间还要乘个常数
有的带删除操作的题我们可以考虑垃圾车回收节点节省空间
有了这些我们可以完成[模板]可持久化平衡树
其他平衡树的题应该都可以写了嗯
end
[note]fhq_treap的更多相关文章
- 三星Note 7停产,原来是吃了流程的亏
三星Note 7发售两个月即成为全球噩梦,从首炸到传言停产仅仅47天.所谓"屋漏偏逢连天雨",相比华为.小米等品牌对其全球市场的挤压.侵蚀,Galaxy Note 7爆炸事件这场连 ...
- 《Note --- Unreal --- MemPro (CONTINUE... ...)》
Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用"Launch" button进行加载自己待检测的application,目前支持的平台为 ...
- 《Note --- Unreal 4 --- Sample analyze --- StrategyGame(continue...)》
---------------------------------------------------------------------------------------------------- ...
- [LeetCode] Ransom Note 赎金条
Given an arbitrary ransom note string and another string containing letters from all th ...
- Beginning Scala study note(9) Scala and Java Interoperability
1. Translating Java Classes to Scala Classes Example 1: # a class declaration in Java public class B ...
- Beginning Scala study note(8) Scala Type System
1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the h ...
- Beginning Scala study note(7) Trait
A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...
- Beginning Scala study note(6) Scala Collections
Scala's object-oriented collections support mutable and immutable type hierarchies. Also support fun ...
- Beginning Scala study note(5) Pattern Matching
The basic functional cornerstones of Scala: immutable data types, passing of functions as parameters ...
随机推荐
- HDU4911:Inversion
Problem Description bobo has a sequence a1,a2,-,an. He is allowed to swap two adjacent numbers for n ...
- MSSQL数据库导入导出大全二(SQL语句)
Excel文件导入数据库多个Sheet if exists(select 1 from sysobjects where name=N'p_import_excel' and type='P')dro ...
- Layer 初始
Layer 初始 介绍:很不错的一个弹出框解决方案 丰富多样的Web弹出层组件,可轻松实现Alert/Confirm/Prompt/普通提示/页面区块/iframe/tips等等几乎所有的弹出交互.目 ...
- Linux上安装tomcat、jdk
一.tomcat [上传 yum -y install lrzsz] 1.tar zxvf apache-tomcat-7.0.57.tar.gz 2. mv apache-tomcat-7.0.57 ...
- js中的string.format函数代码
String.prototype.format = function(args) { if (arguments.length > 0) { var result = this; if (arg ...
- 如何为Apache JMeter开发插件(二)—第一个JMeter插件
文章内容转载于:http://lib.csdn.net/article/softwaretest/25700,并且加上个人一些截图 本篇将开启为JMeter开发插件之旅,我们选择以Function(函 ...
- SubVersion(SVN)的安装配置使用
一. SubVersion服务器端安装 安装软件:Setup-Subversion-1.6.4.msi,下载地址:http://subversion.tigris.org/servlets/Proje ...
- hdu 5348 MZL's endless loop
给一个无向图(事实上是有向的.可是没有指定边的方向),你须要指定边的方向,使得每一个点入度和出度相差不超过1. 事实上就是找很多条路径.合起来能走完这个图..先统计各个顶点的度.度为奇数必是起点或终点 ...
- 2.JAVA编程思想——一切都是对象
一切都是对象 欢迎转载.转载请标明出处:http://blog.csdn.net/notbaron/article/details/51040221 虽然以C++为基础,但 Java 是一种更纯粹的面 ...
- surface4 笔盖失灵的解决方案
http://tieba.baidu.com/p/3670357234 先找到设备管理器,找到蓝牙,删除里面所有的设备.然后重启. 之后再次找到蓝牙,匹配pen.就可以用了. 解决的前提是:我确定笔帽 ...