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. 2017.4.18 putty和fileZilla的使用

    putty:用来连接环境. fileZila:用来传递文件. (1)连接环境 centOS 7 点击putty.exe,输入地址.用户名.密码进行连接.端口输入22.用账号和密码登录. 进入到目录下, ...

  2. 转:Eclipse自动补全功能轻松设置

    Eclipse自动补全功能轻松设置 || 不需要修改编辑任何文件 2012-03-08 21:29:02|  分类: Java |  标签:eclipse  自动补全  设置  |举报|字号 订阅   ...

  3. 算法导论(Introduction to Algorithms )— 第十二章 二叉搜索树— 12.1 什么是二叉搜索树

    搜索树数据结构支持很多动态集合操作,如search(查找).minmum(最小元素).maxmum(最大元素).predecessor(前驱).successor(后继).insert(插入).del ...

  4. Shell 进度条效果的一个实现

    #!/bin/bash processBar() { now=$ all=$ percent=`awk BEGIN'{printf "%f", ('$now'/'$all')}'` ...

  5. selenium从入门到应用 - 2,简单线性脚本的编写

    本系列所有代码 https://github.com/zhangting85/simpleWebtest 本文将介绍一个Java+TestNG+Maven+Selenium的web自动化测试脚本环境下 ...

  6. flashplayer

    http://www.adobe.com/support/flashplayer/downloads.html

  7. 编辑mac系统环境变量后保存,提示没有权限用到下面这个命令

    编辑的文件是vim /etc/paths :w !sudo tee % %代表当前编辑文件名 MAC:查看端口占用情况: lsof -i tcp: list open files lsof -i 用以 ...

  8. App功能测试的7大注意点

    转载于:https://mp.weixin.qq.com/s/27DZ1EQVpl-gb4S7n-He4g 01 运行 1)App安装完成后的试运行,可正常打开软件. 2)App打开测试,是否有加载状 ...

  9. Ubuntu 下修改 Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1 for ServerName

    在Ubuntu上安装Apache,每次重启,都会出现以下错误提示: Could not reliably determine the server’s fully qualified domain n ...

  10. Android+git+hudson+gradle持续集成

    linux 主机   android sdk安装忽略 jdk安装忽略 hudson安装忽略 gradle安装 1:下载相应的gradle(这里是gradle-2.10-all.zip)  2 :  解 ...