[学习笔记] fhq Treap 平衡树

fhq Treap 也叫无旋Treap (好像?我也不知道)

反正我带旋 Treap 是不会滴,其他的平衡树也不会(但是会平板电视)

fhq Treap 好写,码量小,缺点是常数比较大

定义

二叉搜索树

二叉搜索树是一种二叉树的树形数据结构,其定义如下:

  1. 空树是二叉搜索树。

  2. 若二叉搜索树的左子树不为空,则其左子树上所有点的附加权值均小于其根节点的值。

  3. 若二叉搜索树的右子树不为空,则其右子树上所有点的附加权值均大于其根节点的值。

  4. 二叉搜索树的左右子树均为二叉搜索树。

至于二叉搜索树怎么写我也不知道

但是由于可以构造数据使得二叉搜索树退化成一条链所以平衡树就应运而生了

平衡树是通过左旋和右旋各种奇怪的操作使左子树和右子树的高度最多相差 1 的二叉搜索树

Treap 就是一种弱平衡的平衡树

Treap 顾名思义就是 Tree + Heap 是加入了堆来防止二叉搜索树退化(说白了就是随机化

其中,二叉搜索树的性质是:

左子节点的值( val \textit{val} val)比父节点大
右子节点的值( val \textit{val} val)比父节点小(当然这也是可以反过来的)

堆的性质是:

子节点值( key \textit{key} key)比父节点大或小(取决于是小根堆还是大根堆)
不难看出,如果用的是同一个值,那这两种数据结构的性质是矛盾的,所以我们再在搜索树的基础上,引入一个给堆的值 key \textit{key} key。对于 val \textit{val} val 值,我们维护搜索树的性质,对于 key \textit{key} key 值,我们维护堆的性质。其中 key \textit{key} key 这个值是随机给出的。

搬个 OI-Wiki 的图片
在这里插入图片描述
Treap 的核心操作是左旋和右旋 而 fhq Treap 则是不带旋的 Treap,很多情况下会一些操作好写很多

fhq Treap

fhq Treap 的核心操作是分裂 ( s p l i t split split) 和 合并 ( m e r g e merge merge)

节点信息

一个节点中的信息应该很好想罢,值 v a l val val ,键值 k e y key key, 左儿子 l l l ,右儿子 r r r 以及子树大小 s i z siz siz

struct treap{int val,key,siz,l,r;
}fhq[N << 1];

建立新节点

建立一个新节点其实就是把一个节点初始化掉

int new_treap(int val){fhq[++cnt].val = val;fhq[cnt].key = rand();fhq[cnt].siz = 1;return cnt;
}

很好理解对吧

更新父节点信息

其实就和线段树的 p u s h _ u p push \_ up push_up操作是一样的

void push_up(int pos){fhq[pos].siz = fhq[fhq[pos].l].siz + fhq[fhq[pos].r].siz + 1;
}

分裂

分裂操作有两种,一种是按值分裂,把所有值小于等于 v a l val val 的分裂成一颗树,把值 大于 v a l val val分裂成一颗树;一种是按大小分裂,把小于等于给定大小的分裂成一棵树,大于给定大小的分裂成一颗树

一般把 fhq Treap 当正常平衡树使用的时候都是用按值分裂

直接看代码理解罢

void split(int pos, int val, int& x, int& y){//因为是一棵树分裂成两颗树,返回pair会比较麻烦,所以直接引用一下 if(!pos) {//到底了不能分裂 x = y = 0;return;}if(fhq[pos].val <= val){//小于val的分裂到x树去 x = pos;split(fhq[pos].r, val, fhq[pos].r, y);//右子树继续分裂 }else{y = pos;//大于val到y树去 split(fhq[pos].l,val,x,fhq[pos].l);//左子树继续分裂 }push_up(pos);
}

合并

合并当然就是分裂反过来噜~~

int merge(int x, int y){//注意这里x树是分裂出来小的那个树 if(!x || !y) return x+y;//如果x为空就返回y,如果y没有就返回x,如果两个都没有就返回0 if(fhq[x].key > fhq[y].key){//x的键值大,y并到x的右子树去 fhq[x].r = merge(fhq[x].r, y);push_up(x);return x;}else{fhq[y].l = merge(x,fhq[y].l);//y的键值大,x并到y的左子树去 push_up(y);return y;}
}

平衡树常规操作

前面两个操作就很短对吧,后面还要短

插入一个值 val

插入分两步

  1. 把树按 v a l val val 分裂成两棵树
  2. v a l val val 和小于等于 v a l val val 那棵树合并,再合并回去
void insert(int val){int x,y;split(root,val,x,y);root = merge(merge(x,new_treap(val)),y);
}

删除一个值 val

删除分为三步

  1. v a l val val 分裂成两棵树
  2. 把小于等于 v a l val val 的那棵树再按 v a l − 1 val-1 val1 分裂成两棵树(这样我们就得到了全是 v a l val val 的一棵树)
  3. 把全是 v a l val val 的那棵树的根节点删掉(合并左子树和右子树就可以了)
  4. 把剩下的树按顺序合并回去
void del(int val){int x,y,z;split(root,val,x,z);split(x,val-1,x,y);y = merge(fhq[y].l,fhq[y].r);root = merge(merge(x,y),z);
}

查询 val 的排名

这个也很简单啊,就两步

  1. 把树按 v a l − 1 val-1 val1 分裂
  2. 小的那棵树的 s i z + 1 siz+1 siz+1 就可以了
  3. 记得合并回去
void get_rank(int val){int x,y;split(root,val-1,x,y);cout << fhq[x].siz+1 << endl;root = merge(x,y);
}

查询排名为 rank 的值

这个稍微麻烦一点

void get_num(int rank){int now = root;while(now){if(fhq[fhq[now].l].siz+1 == rank) break;else if(fhq[fhq[now].l].siz >= rank) now = fhq[now].l;else{rank -= fhq[fhq[now].l].siz+1;now = fhq[now].r;}}cout << fhq[now].val << endl;
}

查找前驱/后继

void pre(int val){int x,y;split(root,val-1,x,y);int now = x;while(fhq[now].r) now = fhq[now].r;cout << fhq[now].val << endl;root = merge(x,y);
}
void nxt(int val){int x,y;split(root,val,x,y);int now = y;while(fhq[now].l){now = fhq[now].l;}cout << fhq[now].val << endl;root = merge(x,y);
}

板子传送门

Code

#include <bits/stdc++.h>
const int N = 1e5+10;
using namespace std;
struct treap{int val,key,siz,l,r;
}fhq[N << 1];
int cnt = 0,root;
int new_treap(int val){fhq[++cnt].val = val;fhq[cnt].key = rand();fhq[cnt].siz = 1;return cnt;
}
void push_up(int pos){fhq[pos].siz = fhq[fhq[pos].l].siz + fhq[fhq[pos].r].siz + 1;
}
void split(int pos, int val, int& x, int& y){//因为是一棵树分裂成两颗树,返回pair会比较麻烦,所以直接引用一下 if(!pos) {//到底了不能分裂 x = y = 0;return;}if(fhq[pos].val <= val){//小于val的分裂到x树去 x = pos;split(fhq[pos].r, val, fhq[pos].r, y);//右子树继续分裂 }else{y = pos;//大于val到y树去 split(fhq[pos].l,val,x,fhq[pos].l);//左子树继续分裂 }push_up(pos);
}
int merge(int x, int y){//注意这里x树是分裂出来小的那个树 if(!x || !y) return x+y;//如果x为空就返回y,如果y没有就返回x,如果两个都没有就返回0 if(fhq[x].key > fhq[y].key){//x的键值大,y并到x的右子树去 fhq[x].r = merge(fhq[x].r, y);push_up(x);return x;}else{fhq[y].l = merge(x,fhq[y].l);//y的键值大,x并到y的左子树去 push_up(y);return y;}
}
void insert(int val){int x,y;split(root,val,x,y);root = merge(merge(x,new_treap(val)),y);
}
void del(int val){int x,y,z;split(root,val,x,z);split(x,val-1,x,y);y = merge(fhq[y].l,fhq[y].r);root = merge(merge(x,y),z);
}
void get_rank(int val){int x,y;split(root,val-1,x,y);cout << fhq[x].siz+1 << endl;root = merge(x,y);
}
void get_num(int rank){int now = root;while(now){if(fhq[fhq[now].l].siz+1 == rank) break;else if(fhq[fhq[now].l].siz >= rank) now = fhq[now].l;else{rank -= fhq[fhq[now].l].siz+1;now = fhq[now].r;}}cout << fhq[now].val << endl;
}
void pre(int val){int x,y;split(root,val-1,x,y);int now = x;while(fhq[now].r) now = fhq[now].r;cout << fhq[now].val << endl;root = merge(x,y);
}
void nxt(int val){int x,y;split(root,val,x,y);int now = y;while(fhq[now].l){now = fhq[now].l;}cout << fhq[now].val << endl;root = merge(x,y);
}
int n;int main(){cin >> n;while(n--){int op,x;cin >> op >> x;if(op == 1){insert(x);}if(op == 2){del(x);}if(op == 3){get_rank(x);}if(op == 4){get_num(x);}if(op == 5){pre(x);}if(op == 6){nxt(x);}}	return 0;
}

感觉只实现这些不够?那可以去看看下一篇fhq 实现文艺平衡树

如果有任何不足之处或者疑问,欢迎在评论区提出

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/120230.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用QT操作Excel 表格的常用方法

VBA 简介 Microsoft Office软件通常使用VBA来扩展Windows的应用程序功能&#xff0c;Visual Basic for Applications&#xff08;VBA&#xff09;是一种Visual Basic的一种宏语言。 在VBA的参考手册中就可以看到具体函数、属性的用法&#xff0c;Qt操作Excel主要通过 QAxObj…

培训机构如何利用小程序提升服务质量

近年来&#xff0c;小程序成为了许多企业和机构进行线上业务拓展的新方式。对于培训机构来说&#xff0c;构建一个具有吸引力的小程序可以帮助他们更好地与学员进行互动和沟通&#xff0c;并提供更便捷的学习服务。那么&#xff0c;如何使用第三方制作平台来构建一个具有吸引力…

vscode新建vue3文件模板

输入快捷新建的名字 enter 确认后在文件中输入以下内容 {// Place your snippets for vue here. Each snippet is defined under a snippet name and has a prefix, body and// description. The prefix is what is used to trigger the snippet and the body will be expand…

32 实验三十二、OCL电路的研究

一、题目 仿真电路如图1所示。利用 Multisim 研究下列问题&#xff1a; &#xff08;1&#xff09;负载 R 6 R_6 R6​ 上能获得的最大输出功率&#xff1b; &#xff08;2&#xff09;电容 C 1 C_1 C1​、 C 2 C_2 C2​ 的作用&#xff1b; &#xff08;3&#xff09;当输入…

31 WEB漏洞-文件操作之文件包含漏洞全解

目录 文件包含漏洞原理检测类型利用修复 本地包含-无限制&#xff0c;有限制远程包含-无限制&#xff0c;有限制各种协议流玩法文章介绍读取文件源码用法执行php代码用法写入一句话木马用法每个脚本支持的协议玩法 演示案例某CMS程序文件包含利用-黑盒CTF-南邮大&#xff0c;i春…

春秋云镜 CVE-2018-12530

春秋云镜 CVE-2018-12530 Metinfo 6.0.0任意文件删除 靶标介绍 Metinfo 6.0.0任意文件删除。后台密码&#xff1a;f2xWcke5KN6pfebu 启动场景 漏洞利用 /admin进入管理后台&#xff0c;admin/f2xWcke5KN6pfebu /admin/app/batch/csvup.php?fileFieldtest-1&fliename…

手机无人直播软件在苹果iOS系统中能使用吗?

在现代社交媒体的时代&#xff0c;直播带货已经成为了一种热门的销售途径。通过直播&#xff0c;人们可以远程分享自己的商品&#xff0c;与观众进行互动&#xff0c;增强沟通和参与感。而如今&#xff0c;手机无人直播软件更是成为了直播带货领域的一项火爆的技术。那么&#…

参编三大金融国标,奇富科技以技术促行业规范化演进

近期&#xff0c;由中国互联网金融协会领导制定的《互联网金融智能风险防控技术要求》《互联网金融个人网络消费信贷信息披露》《互联网金融个人身份识别技术要求》三项国家标准颁布&#xff0c;由国家市场监督管理总局、国家标准化管理委员会发布&#xff0c;奇富科技作为核心…

机械零件保养3d模拟演示打消客户购买顾虑

复杂机械的工作运转是复杂的&#xff0c;想要对机械有深度的理解和迭代&#xff0c;必须了解它的运转原理及参数&#xff0c;复杂机械运行原因教学存在着不可视、系统庞杂及知识点多等弊病&#xff0c;3D虚拟展示是基于web3d网页运行的三维页面&#xff0c;可以将复杂机械运行过…

2023年全国职业院校技能大赛信息安全管理与评估网络安全渗透任务书

全国职业院校技能大赛 高等职业教育组 信息安全管理与评估 任务书 模块三 网络安全渗透、理论技能与职业素养 比赛时间及注意事项 本阶段比赛时长为180分钟&#xff0c;时间为9:00-12:00。 【注意事项】 &#xff08;1&#xff09;通过找到正确的flag值来获取得分&#xff0c;f…

【C语言】文件操作详解

文章目录 前言一、文件是什么二、文件具体介绍1.文件名2.文件类型3.文件缓冲区4.文件指针5.文件的打开和关闭 三、文件的顺序读写1.字符输入函数&#xff08;fgetc&#xff09;2.字符输出函数&#xff08;fputc&#xff09;3.文本行输入函数&#xff08;fgets&#xff09;4.文本…

Linux--I/O复用之select

目录 一&#xff1a;概念 二&#xff1a;使用 三&#xff1a;参数介绍&#xff1a; 1.ndfs&#xff1a; 2.fd_set类型&#xff1a; 3.readfds&#xff1a; 4.writefds&#xff1a; 5.exceptfds&#xff1a; 6.timeout&#xff1a; 7.返回值&#xff1a; 四&#xff1…

C# 如何读取dxf档案

需求来源&#xff1a; 工作中&#xff0c;客户提供一张CAD导出的dxf 档案&#xff0c;然后需要机器人将其转成点位&#xff0c;走到对应的位置。 下面介绍一下dxf档案到底是什么&#xff1f;以及语法规则。 dxf 格式介绍&#xff1a;DXF 格式 dxf LINE 格式。 其实上述文档…

【java】【项目实战】[外卖十二]【完结】项目优化(前后端分离开发)

目录 一、问题说明 二、前后端分离开发 1、介绍 2、开发流程 3、前端技术栈 三、Yapi 1、介绍 2、部署 3、使用 3.1 添加项目​编辑 3.2 添加分类​编辑 3.3 添加接口 3.4 运行 3.5 导出接口 3.6 导入数据 四、Swagger 1、介绍 2、使用方式 2.1 pom 2.2 导入…

软件测试/测试开发丨Selenium Web自动化多浏览器处理

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27185 一、多浏览器测试介绍 1.1、多浏览器测试背景 用户使用的浏览器(firefox,chrome,IE 等)web 应用应该能在任何浏览器上正常的工作&#xff0c;这样…

1.1 计算机网络在信息时代中的作用

思维导图&#xff1a; 正文&#xff1a; 我的理解&#xff1a; 这段话是一本书或课程的第一章简介&#xff0c;它的目的是为读者或学生提供一个关于计算机网络基础知识的框架或大纲。 首先&#xff0c;它强调了这章是整本书的一个概览&#xff0c;会先介绍计算机网络在信息时…

微服务·架构组件之服务注册与发现-Nacos

微服务组件架构之服务注册与发现之Nacos Nacos服务注册与发现流程 服务注册&#xff1a;Nacos 客户端会通过发送REST请求的方式向Nacos Server注册自己的服务&#xff0c;提供自身的元数据&#xff0c;比如ip地址、端口等信息。 Nacos Server接收到注册请求后&#xff0c;就会…

【力扣】304. 二维区域和检索 - 矩阵不可变 <二维前缀和>

目录 【力扣】304. 二维区域和检索 - 矩阵不可变二维前缀和理论初始化计算面积 题解 【力扣】304. 二维区域和检索 - 矩阵不可变 给定一个二维矩阵 matrix&#xff0c;以下类型的多个请求&#xff1a; 计算其子矩形范围内元素的总和&#xff0c;该子矩阵的 左上角 为 (row1, …

怎么把pdf转换成高清图片?

怎么把pdf转换成高清图片&#xff1f;最近&#xff0c;我的同事遇到了一个问题&#xff0c;现在她需要将一些pdf文件转换成高清的图片&#xff0c;这件事情让让她感到非常无助&#xff0c;因为她非常着急需要将这些文件转换为图片格式&#xff0c;以便更好的在今后的工作中进行…

R语言Meta分析核心技术

Meta分析是针对某一科研问题&#xff0c;根据明确的搜索策略、选择筛选文献标准、采用严格的评价方法&#xff0c;对来源不同的研究成果进行收集、合并及定量统计分析的方法&#xff0c;最早出现于“循证医学”&#xff0c;现已广泛应用于农林生态&#xff0c;资源环境等方面。…