$FHQ\_Treap$是平衡树的一种,它不仅支持几乎所有的平衡树的操作,而且实现特别简单,总共只有两个操作。这里来简单介绍一下。

基本操作

$FHQ\_Treap$和$Treap$一样是需要用随机值来维护树的形态的,但是$FHQ\_Treap$不需要旋转来调整形态,而是用$Split$和$Merge$来实现,也就是分离与合并,也就是这两种操作,完成了$FHQ\_Treap$的所有操作。

分离(Split)

把一棵平衡树分离成两棵,从而方便插入和删除。分离有两种做法,一种是按权值分离,一种是按子树大小分离,根据情况选择。

权值分离版:

void split(int rt,int k,int &x,int &y)
{
if( !rt ) x=y=;
else {
if( val[rt]<=k ) x=rt, split(ch[rt][],k,ch[rt][],y);
else y=rt, split(ch[rt][],k,x,ch[rt][]);
pushup(rt);
}
}

子树大小版:

void split(int rt,int k,int &x,int &y)
{
if( !rt ) x=, y=;
else {
pushdown(rt);
if( siz[ch[rt][]]<k ) {
x=rt, split(ch[rt][],k-siz[ch[rt][]]-,ch[rt][],y);
} else {
y=rt, split(ch[rt][],k,x,ch[rt][]);
}
pushup(rt);
}
}

合并(merge)

合并操作与左偏树的合并类似,按照优先级合并,把优先级高的作为父节点。当然,合并的时候,函数中的两个参数$x,y$要按照顺序,$x$是权值较小的,$y$是权值较大的,因为合并的时候是按照随机值来确定优先级的。(当然在函数中交换也行,不过常数大些)

int merge(int x,int y)
{
if( !x || !y ) return x+y;
if( p[x]<p[y] ) {
ch[x][]=merge(ch[x][],y); pushup(x);
return x;
} else {
ch[y][]=merge(x,ch[y][]); pushup(y);
return y;
}
}

平衡树的其他操作的实现

插入新节点(insert)

先把树按照新结点的权值分离,然后再把新结点当作一棵树与两个分离出来的树合并。

inline int neo(int v)
{
val[++tot]=v;
siz[tot]=; p[tot]=rand();
return tot;
} inline void insert(int v)
{
int x,y;
split(root,v,x,y);
root=merge(merge(x,neo(v)),y);
}

删除节点(delete)

按删除节点的权值$v$把树分离成小于$v$,等于$v$,大于$v$三段,然后去掉等于$v$的树的根节点(也就是直接合并根节点的左右子树),然后合并回来。

inline void delet(int v)
{
int x,y,z;
split(root,v,x,y);
split(x,v-,x,z);
z=merge(ch[z][],ch[z][]);
root=merge(x,merge(z,y));
}

查询权值为$k$的节点排名

按照权值分离然后输出左子树大小$+1$即可。

inline void kth(int k)
{
int x,y;
split(root,k-,x,y);
printf("%d\n",siz[x]+);
root=merge(x,y);
}

查询$k$小值

和其他平衡树一样搜索、递归。

int rank(int rt,int k)
{
if( siz[ch[rt][]]==k- ) return val[rt];
if( siz[ch[rt][]]>=k ) return rank(ch[rt][],k);
return rank(ch[rt][],k-siz[ch[rt][]]-);
}

查询前驱后继

按权值分离然后查询分离出的子树的最大/最小值就行了。

inline void prev(int v)
{
int x,y;
split(root,v-,x,y);
printf("%d\n",rank(x,siz[x]));
root=merge(x,y);
} inline void nex(int v)
{
int x,y;
split(root,v,x,y);
printf("%d\n",rank(y,));
root=merge(x,y);
}

可以看出,$FHQ\_Treap$的操作都非常简短,仅仅用了两种核心操作就实现了其他平衡树的能实现的全部功能,非常方便。在绝大多数情况下需要使用平衡树的时候都可以直接用$FHQ\_Treap$,既容易理解又方便实现,而且也很容易$Debug$。

同时,$FHQ\_Treap$也是支持可持久化的,不过这里就不再赘述(我会告诉你其实我也没写过?)。

完整模板

洛谷模板题

//It is made by HolseLee on 27th Sep 2018
//Luogu.org P3369
#include<bits/stdc++.h>
using namespace std; const int N=1e5+;
int n,root,tot;
int val[N],ch[N][],p[N],siz[N]; inline int read()
{
char ch=getchar(); int num=; bool flag=false;
while( ch<'' || ch>'' ) {
if( ch=='-' ) flag=true; ch=getchar();
}
while( ch>='' && ch<='' ) {
num=num*+ch-''; ch=getchar();
}
return flag ? -num : num;
} inline void pushup(int rt)
{
siz[rt]=siz[ch[rt][]]+siz[ch[rt][]]+;
} void split(int rt,int k,int &x,int &y)
{
if( !rt ) x=y=;
else {
if( val[rt]<=k ) x=rt, split(ch[rt][],k,ch[rt][],y);
else y=rt, split(ch[rt][],k,x,ch[rt][]);
pushup(rt);
}
} int merge(int x,int y)
{
if( !x || !y ) return x+y;
if( p[x]<p[y] ) {
ch[x][]=merge(ch[x][],y); pushup(x);
return x;
} else {
ch[y][]=merge(x,ch[y][]); pushup(y);
return y;
}
} inline int neo(int v)
{
val[++tot]=v;
siz[tot]=; p[tot]=rand();
return tot;
} inline void insert(int v)
{
int x,y;
split(root,v,x,y);
root=merge(merge(x,neo(v)),y);
} inline void delet(int v)
{
int x,y,z;
split(root,v,x,y);
split(x,v-,x,z);
z=merge(ch[z][],ch[z][]);
root=merge(x,merge(z,y));
} inline void kth(int k)
{
int x,y;
split(root,k-,x,y);
printf("%d\n",siz[x]+);
root=merge(x,y);
} int rank(int rt,int k)
{
if( siz[ch[rt][]]==k- ) return val[rt];
if( siz[ch[rt][]]>=k ) return rank(ch[rt][],k);
return rank(ch[rt][],k-siz[ch[rt][]]-);
} inline void prev(int v)
{
int x,y;
split(root,v-,x,y);
printf("%d\n",rank(x,siz[x]));
root=merge(x,y);
} inline void nex(int v)
{
int x,y;
split(root,v,x,y);
printf("%d\n",rank(y,));
root=merge(x,y);
} int main()
{
srand();
n=read(); int opt;
for(int i=; i<=n; ++i) {
opt=read();
if( opt== ) insert(read());
else if( opt== ) delet(read());
else if( opt== ) kth(read());
else if( opt== ) printf("%d\n",rank(root,read()));
else if( opt== ) prev(read());
else nex(read());
}
return ;
}

神仙数据结构——FHQ_Treap的更多相关文章

  1. fhq_treap 学习笔记

    前言:昨天写NOIp2017队列,写+调辗转了3h+,不知道怎么的,就点进了一个神仙的链接,便在今日学习了神仙的fhq_treap. 简介:fhq_treap功能强大,支持splay支持的所有操作,代 ...

  2. 浅谈左偏树在OI中的应用

    Preface 可并堆,一个听起来很NB的数据结构,实际上比一般的堆就多了一个合并的操作. 考虑一般的堆合并时,当我们合并时只能暴力把一个堆里的元素一个一个插入另一个堆里,这样复杂度将达到\(\log ...

  3. 【题解】P4247 [清华集训]序列操作(线段树修改DP)

    [题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...

  4. fhq-treap简介

    \(fhq-treap\)是个好东西啊!无旋转\(treap\)果然是好写,而且还是比较好理解的. 这种数据结构是由神犇fhq发明的.\(Think\ functional!\) fhq神犇说,函数式 ...

  5. thupc & cts & apio & thusc 游记 (北京17日游记)

    thupc & cts & apio & thusc 游记 (北京17日游记) Day 0 和隔壁校两人py了一下,六个人组了两队,(左哼哼)与(右哼哼),我和Camoufla ...

  6. [日常] SNOI2019场外VP记

    SNOI2019场外VP记 教练突然说要考一场别省省选来测试水平...正好还没看题那就当VP咯w... Day 1 八点开题打 .vimrc. 先看了看题目名...一股莫名鬼畜感袭来... 怎么T1就 ...

  7. 冲刺CSP-S集训考试反思+其它乱写(密码私信)

    RT.开坑. 10.1 开门黑23333. 放假回来稍困,而且感冒似乎愈加严重,导致我正常考试基本睁不开眼.一个小时勉强把题读懂,神志恍惚如斯. 看T2觉得估计又是各种推柿子堆定理的数学大题,写了个暴 ...

  8. csp-s模拟测试52-53

    留坑.... 改完题再说吧. 留坑....最近考得什么鬼??模拟53T1 u(差分) 一道差分题????然而考场没有想到如何维护斜率上的差分,事后经miemeng和cyf的生(xuan)动(xue)讲 ...

  9. 2021.8.24考试总结[NOIP47]

    T1 prime 发现只需筛小于等于$mid(\sqrt r,k)$的质数,之后用这些质数筛掉区间内不合法的数即可. $code:$ 1 #include<bits/stdc++.h> 2 ...

随机推荐

  1. Go 语言中的方法,接口和嵌入类型

    https://studygolang.com/articles/1113 概述 在 Go 语言中,如果一个结构体和一个嵌入字段同时实现了相同的接口会发生什么呢?我们猜一下,可能有两个问题: 编译器会 ...

  2. EasyUI 格式化列

    以下实例格式化在 easyui DataGrid 里的列数据,并使用自定义列的 formatter,如果价格小于 20 就将文本变为红色. 为了格式化一个数据网格(DataGrid)列,我们需要设置 ...

  3. 解决 django 博客归档 “Are time zone definitions for your database and pytz installed?”的错误

    修改 project 中的settings 文件,问题解决! # USE_TZ = True USE_TZ = False # LANGUAGE_CODE = 'en-us' LANGUAGE_COD ...

  4. python中的BeautifulSoup使用小结

    1.安装 pip install beautifulsoup4 2.代码文件中导入 from bs4 import BeautifulSoup 3. 解析器 使用方法 优势 劣势 Python标准库 ...

  5. OpenStack 存储服务 Cinder存储节点部署NFS(十七)

    Cinder存储节点部署 1.安装软件包 yum install -y nfs-utils rpcbind 提示:早期版本安装portmap nfs-utils :包括基本的NFS命令与监控程序 rp ...

  6. python获取指定目录下所有文件名os.walk和os.listdir

    python获取指定目录下所有文件名os.walk和os.listdir 觉得有用的话,欢迎一起讨论相互学习~Follow Me os.walk 返回指定路径下所有文件和子文件夹中所有文件列表 其中文 ...

  7. 【转】在Mac OS X 10.8中配置Apache + PHP + MySQL

    CHENYILONG Blog 在Mac OS X 10.8中配置Apache + PHP + MySQL 在Mac OS X 10.8中配置Apache+PHP+MySQL的内容包括: 配置Apac ...

  8. 永不改变的PCB设计黄金法则

    尽管目前半导体集成度越来越高,许多应用也都有随时可用的片上系统,同时许多功能强大且开箱即用的开发板也越来越可轻松获取,但许多使用案例中电子产品的应用仍然需要使用定制PCB.在一次性开发当中,即使一个普 ...

  9. RabbitMq Queue一些方法及参数

    方法: 1.QueueDeclare 声明队列 public static QueueDeclareOk QueueDeclare(String queue, Boolean durable, Boo ...

  10. 安装.NET Framework返回1603错误的解决办法

    昨天正在忙其它事情,实然同事向我反馈TFS上的文档无法浏览查看.第一反映是他的机器环境问题,让他试了下其它项目的文档也无法查看,后来在我电脑上也尝试了一下,果然无法查看项目文档,看来是TFS出了问题. ...