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.9.15 postgresql批量插入造成冲突后执行更新

    参考来自:https://stackoverflow.com/questions/40647600/postgresql-multi-value-upserts/46233907#46233907 1 ...

  2. [SCSS] Create a gradient with a Sass loop

    In this lesson, you will learn how to iteratively generate CSS selectors and attributes using Sass l ...

  3. C2:抽象工厂 Abstract Factory

    提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. 应用场景: 一系列相互依赖的对象有不同的具体实现.提供一种“封装机制”来避免客户程序和这种“多系列具体对象创建工作”的紧耦合 UM ...

  4. Asp.net Mvc使用PagedList分页

    git:https://github.com/troygoode/PagedList 1. Nuget 安装package watermark/2/text/aHR0cDovL2Jsb2cuY3Nkb ...

  5. web前端性能优化汇总

    一.概述 web前端性能优化主要点为:减少HTTP请求,减小请求文件大小.其他优化. 二.优化细节 1.减少HTTP请求 (1)使用缓存 (2)雪碧图 (3)合并文件 (4)将javascript和c ...

  6. js 将内容复制到剪贴板

      js 将内容复制到剪贴板 CreationTime--2018年7月1日15点06分 Author:Marydon function copyToClipboard(txt) { if(windo ...

  7. Hibernate核心类和接口具体介绍

    一.hiobernate核心类和接口预览图 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveGxnZW4xNTczODc=/font/5a6L5L2T/fo ...

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

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

  9. ZAP介绍

    Zed Attack Proxy简写为ZAP,是一个简单易用的渗透测试工具,是发现Web应用中的漏洞的利器,更是渗透测试爱好者的好东西.ZAP下载地址:https://www.owasp.org/in ...

  10. HDU 1014 Uniform Generator 题解

    找到规律之后本题就是水题了.只是找规律也不太easy的.证明这个规律成立更加不easy. 本题就是求step和mod假设GCD(最大公约数位1)那么就是Good Choice,否则为Bad Choic ...