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的更多相关文章

  1. 三星Note 7停产,原来是吃了流程的亏

    三星Note 7发售两个月即成为全球噩梦,从首炸到传言停产仅仅47天.所谓"屋漏偏逢连天雨",相比华为.小米等品牌对其全球市场的挤压.侵蚀,Galaxy Note 7爆炸事件这场连 ...

  2. 《Note --- Unreal --- MemPro (CONTINUE... ...)》

    Mem pro 是一个主要集成内存泄露检测的工具,其具有自身的源码和GUI,在GUI中利用"Launch" button进行加载自己待检测的application,目前支持的平台为 ...

  3. 《Note --- Unreal 4 --- Sample analyze --- StrategyGame(continue...)》

    ---------------------------------------------------------------------------------------------------- ...

  4. [LeetCode] Ransom Note 赎金条

    
Given
 an 
arbitrary
 ransom
 note
 string 
and 
another 
string 
containing 
letters from
 all 
th ...

  5. 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 ...

  6. 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 ...

  7. Beginning Scala study note(7) Trait

    A trait provides code reusability in Scala by encapsulating method and state and then offing possibi ...

  8. Beginning Scala study note(6) Scala Collections

    Scala's object-oriented collections support mutable and immutable type hierarchies. Also support fun ...

  9. Beginning Scala study note(5) Pattern Matching

    The basic functional cornerstones of Scala: immutable data types, passing of functions as parameters ...

随机推荐

  1. java Map根据value排序

    通用方法 public class MapUtil { public static <K, V extends Comparable<? super V>> Map<K, ...

  2. BZOJ 4216 Pig 分块乱搞

    题意:id=4216">链接 方法:分块以节约空间. 解析: 这题坑的地方就是他仅仅有3M的内存限制,假设我们开longlong前缀和是必死的. 所以考虑缩小这个long long数组 ...

  3. Window 7 开 WIFI做热点

    cmd下两个命令即可: C:\Users\lyx>netsh wlan set hostednetwork mode=allow ssid=ACE-PC key=12345678承载网络模式已设 ...

  4. 使用Maven整合SSH总结

    本人自己进行的SSH整合,中间遇到不少问题,特此做些总结,仅供参考. 项目环境: struts-2.3.31 + spring-4.3.7 + hibernate-4.2.21 + maven-3.3 ...

  5. fabric自动发布tomcat线上项目

    现在公司的每个tomcat项目都有测试和生产两个环境,对于经常需要上线的tomcat项目,如用手工更新就非常耗费时间和人力.现用fabric开发了一个自动发布tomcat项目的脚本,该脚本已经在公司使 ...

  6. PHP面试题及答案解析(5)—数据结构与算法

    1.使对象可以像数组一样进行foreach循环,要求属性必须是私有.(Iterator模式的PHP5实现,写一类实现Iterator接口) <?php class Test implements ...

  7. Ubuntu安装sublime test 3 (Build 3126)

    Ubuntu下 Sublime Text 3 (Build 3143) 存在一些bug........ 满心欢喜地更新后, 又默默换回Build 3126 1. 安装 sudo apt-get upd ...

  8. 深入理解Tomcat系列之五:Context容器和Wrapper容器

    前言 Context容器是一个Web项目的代表,主要管理Servlet实例,在Tomcat中Servlet实例是以Wrapper出现的.如今问题是怎样才干通过Context容器找到详细的Servlet ...

  9. C语言学习笔记(七)——其它运算符

     第七章                          其它运算符   逗号运算符 逗号运算符:即顺序点,逗号前先运行.后再运行. for循环的运行次数: for(i=n; i<m; + ...

  10. git 修改远程仓库地址

    以前的老项目需要修改git路径,为了保留之前的上传记录和分支等可以通过以下方法解决这个问题 sourceTree项目远程仓库,直接修改origin路径,然后提交一个commit即可将项目上传到新的gi ...