学习笔记」左偏树

dist 的性质

对于一棵二叉树,我们定义左孩子或右孩子为空的节点为外节点,定义外节点的 distdist 为 11,空节点的 distdist 为 00,不是外节点也不是空节点的 distdist 为其到子树中最近的外节点的距离加一。
一棵根的 distdist 为 xx 的二叉树至少有 2x−12x−1 个节点。此性质所有二叉树都有,并非左偏树特有。
distdist 不是深度,左偏树的深度没有保证,一条向左的链也是左偏树。

左偏树的性质

左偏树是一棵二叉树,并且是“左偏”的,即每个节点左儿子的 distdist 都大于等于右儿子的 distdist。
因此,左偏树中每个节点的 distdist 是它右儿子的 distdist 加一。

变量

int lson[N], rson[N], fa[N], fat[N];
ll val[N], dist[N];

lson: 左孩子(左偏);
rson: 右孩子;
fa: 父节点;
fat: 祖先(并查集);
val: 权值;
dist: 就是 distdist。

操作

  • 合并

int merge(int x, int y) { // 合并if (!x || !y) {return x | y;}if (val[x] > val[y] || (val[x] == val[y] && x > y))swap(x, y);rson[x] = merge(rson[x], y);fat[rson[x]] = fa[rson[x]] = x;if (dist[lson[x]] < dist[rson[x]])swap(lson[x], rson[x]);dist[x] = dist[rson[x]] + 1;return x;
}

if (!x || !y) { return x | y; }
如果与空节点合并,则直接合并即可
if (val[x] > val[y] || (val[x] == val[y] && x > y))
说明这是个小根堆,小元素在上面。
if (dist[lson[x]] < dist[rson[x]]) swap(lson[x], rson[x]);
维护左偏的性质。

  • 删除任意一个节点

左偏树是不支持删除给定权值的点的,只能删除知道点的标号的点。

void earse(int u) { // 删除任意一点int tmp = merge(lson[u], rson[u]), fu = fa[u];fat[tmp] = fa[tmp] = fu;fat[u] = fa[u] = tmp;lson[fu] == u ? lson[fu] = tmp : rson[fu] = tmp;while (fu) {if (dist[lson[fu]] < dist[rson[fu]])swap(lson[fu], rson[fu]);if (dist[fu] == dist[rson[fu]] + 1)return ;dist[fu] = dist[rson[fu]] + 1;fu = fa[fu];}
}

int tmp = merge(lson[u], rson[u]), fu = fa[u]; 先将被删节点的左右孩子合并。
fat[tmp] = fa[tmp] = fu; 处理好父亲和孩子的关系。

while (fu) {if (dist[lson[fu]] < dist[rson[fu]])swap(lson[fu], rson[fu]);if (dist[fu] == dist[rson[fu]] + 1)return ;dist[fu] = dist[rson[fu]] + 1;fu = fa[fu];
}

删除点之后可能不符合左偏性质,需要我们向上修改,直到到根节点或符合左偏性质为止。

  • 查询 uu 点所在堆的堆顶元素的标号

这个操作类似于并查集操作。

int find(int u) { // 查询堆顶的元素的标号return (fat[u] == u || fat[u] == 0) ? u : fat[u] = find(fat[u]);
}
  • 删除 uu 点所在堆的堆顶元素

void pop(int u) { // 弹出 u 点所在对的堆顶元素int g = find(u);earse(g);
}
  • 查询 uu 点所在堆的堆顶元素

ll top(int u) { // 查询 u 点所在堆的堆顶元素int g = find(u);return val[g];
}
  • 建树操作

int build(int n) { // 建树queue<int> q;for (int i = 1; i <= n; ++ i) {q.push(i);}int x, y, z;while (q.size() > 1) {x = q.front(), q.pop();y = q.front(), q.pop();z = merge(x, y), q.push(z);}return q.front();
}

模板

// 左偏树(小根堆)
struct leftist_tree {int lson[N], rson[N], fa[N], fat[N];ll val[N], dist[N];int merge(int x, int y) { // 合并if (!x || !y) {return x | y;}if (val[x] > val[y] || (val[x] == val[y] && x > y))swap(x, y);rson[x] = merge(rson[x], y);fat[rson[x]] = fa[rson[x]] = x;if (dist[lson[x]] < dist[rson[x]])swap(lson[x], rson[x]);dist[x] = dist[rson[x]] + 1;return x;}int find(int u) { // 查询堆顶的元素的标号return (fat[u] == u || fat[u] == 0) ? u : fat[u] = find(fat[u]);}void earse(int u) { // 删除任意一点int tmp = merge(lson[u], rson[u]), fu = fa[u];fat[tmp] = fa[tmp] = fu;fat[u] = fa[u] = tmp;lson[fu] == u ? lson[fu] = tmp : rson[fu] = tmp;while (fu) {if (dist[lson[fu]] < dist[rson[fu]])swap(lson[fu], rson[fu]);if (dist[fu] == dist[rson[fu]] + 1)return ;dist[fu] = dist[rson[fu]] + 1;fu = fa[fu];}}ll top(int u) { // 查询 u 点所在堆的堆顶元素int g = find(u);return val[g];}void pop(int u) { // 弹出 u 点所在对的堆顶元素int g = find(u);earse(g);}int build(int n) { // 建树queue<int> q;for (int i = 1; i <= n; ++ i) {q.push(i);}int x, y, z;while (q.size() > 1) {x = q.front(), q.pop();y = q.front(), q.pop();z = merge(x, y), q.push(z);}return q.front();}
};

pb_ds 中的堆

__gnu_pbds :: priority_queue 

成员函数

 

push(): 向堆中压入一个元素,返回该元素位置的迭代器。
pop(): 将堆顶元素弹出。
top(): 返回堆顶元素。
size(): 返回元素个数。
empty(): 返回是否非空。
modify(point_iterator, const key): 把迭代器位置的 key 修改为传入的 key,并对底层储存结构进行排序。 
erase(point_iterator): 把迭代器位置的键值从堆中擦除。
join(__gnu_pbds :: priority_queue &other): 把 other 合并到 *this 并把 other 清空。

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

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

相关文章

中间件(下)

1、中间件与性能优化的关系&#xff1a; 中间件与性能优化之间存在密切的关系&#xff0c;特别是在构建复杂的分布式系统、处理高并发、实现异步通信等情况下。中间件可以在性能优化方面发挥重要作用&#xff0c;但同时&#xff0c;不当的中间件选择和配置也可能导致性能问题。…

【卡码网】31. 字符串的最大价值 <贪心>

【卡码网】31. 字符串的最大价值 给定一个字符串 S S S&#xff08;S.lenth < 5000&#xff09;&#xff0c;只包含 0 和 1 两个数字&#xff0c;下标从 1 开始&#xff0c;设第 i i i 位的价值为 v a l i val_i vali​&#xff0c;则 v a l i val_i vali​的定义如下&a…

神经网络基础-神经网络补充概念-52-正则化网络的激活函数

概念 正则化是一种用于减少过拟合&#xff08;overfitting&#xff09;的技术&#xff0c;可以在神经网络的各个层次中应用&#xff0c;包括激活函数。激活函数的正则化主要目的是减少神经网络的复杂度&#xff0c;防止网络在训练集上过度学习&#xff0c;从而提高泛化能力。 …

ubuntu20.04 root用户下使用中文输入法——root用户pycharm无法用中文输入法问题

因为一些众所不周知的bug&#xff0c;我的pycharm使用apt或者snap安装都不行了&#xff0c;官网下了“绿色版”&#xff0c;运行pycharm.sh也运行不起来&#xff0c;有个java相关环境报错&#xff0c;jre和jdk都装了&#xff0c;还是有点问题&#xff0c;最后尝试发现可以用roo…

DevOps系列文章之 GitlabCICD自动化部署SpringBoot项目

一、概述 本文主要记录如何通过Gitlab CI/CD自动部署SpringBoot项目jar包。 二、前期准备 准备三台 CentOS7服务器&#xff0c;分别部署以下服务&#xff1a; 序号系统IP服务1CentOS7192.168.56.10Gitlab2CentOS7192.168.56.11Runner &#xff08;安装Docker&#xff09;3Cen…

Spring boot中的线程池-ThreadPoolTaskExecutor

一、jdk的阻塞队列&#xff1a; 二、Spring boot工程的有哪些阻塞队列呢&#xff1f; 1、默认注入的ThreadPoolTaskExecutor 视频解说&#xff1a; 线程池篇-springboot项目中的service层里简单注入ThreadPoolTaskExecutor并且使用_哔哩哔哩_bilibili 程序代码&#xff1a;…

预测算法|改进粒子群算法优化极限学习机IDM-PSO-ELM

回归拟合&#xff1a; 分类 本文是作者的预测算法系列的第四篇&#xff0c;前面的文章中介绍了BP、SVM、RF及其优化&#xff0c;感兴趣的读者可以在作者往期文章中了解&#xff0c;这一篇将介绍——极限学习机 过去的几十年里基于梯度的学习方法被广泛用于训练神经网络&am…

分布式 - 消息队列Kafka:Kafka 消费者消息消费与参数配置

文章目录 1. Kafka 消费者消费消息01. 创建消费者02. 订阅主题03. 轮询拉取数据 2. Kafka 消费者参数配置01. fetch.min.bytes02. fetch.max.wait.ms03. fetch.max.bytes04. max.poll.records05. max.partition.fetch.bytes06. session.timeout.ms 和 heartbeat.interval.ms07.…

使用 pyodbc 解析chrome浏览器导出的书签并保存到 Microsoft Access 数据库

使用 wxPython 和 pyodbc 解析书签并保存到 Microsoft Access 数据库的示例博客&#xff1a; 本篇博客介绍了如何使用 wxPython 和 pyodbc 库创建一个简单的应用程序&#xff0c;用于解析 HTML 文件中的书签并将其保存到 Microsoft Access 数据库中。通过这个示例&#xff0c;您…

【Sklearn】基于梯度提升树算法的数据分类预测(Excel可直接替换数据)

【Sklearn】基于梯度提升树算法的数据分类预测(Excel可直接替换数据) 1.模型原理2.模型参数3.文件结构4.Excel数据5.下载地址6.完整代码7.运行结果1.模型原理 梯度提升树(Gradient Boosting Trees)是一种集成学习方法,用于解决分类和回归问题。它通过将多个弱学习器(通常…

ONNX版本YOLOV5-DeepSort (rknn版本已经Ready)

目录 1. 前言 2. 储备知识 3. 准备工作 4. 代码修改的地方 5.结果展示 1. 前言 之前一直在忙着写文档&#xff0c;之前一直做分类&#xff0c;检测和分割&#xff0c;现在看到跟踪算法&#xff0c;花了几天时间找代码调试&#xff0c;看了看&#xff0c;展示效果比单纯的检…

手写代码-前端面试

GitHub&#xff1a;手写代码集合

HTTP响应状态码大全:从100到511,全面解析HTTP请求的各种情况

文章目录 前言一、认识响应状态码1. 什么是HTTP响应状态码2. Http响应状态码的作用3. 优化和调试HTTP请求的建议 二、1xx 信息响应1. 认识http信息响应2. 常见的信息响应状态码 三、2xx 成功响应1. 认识HTTP成功响应2. 常见的成功响应状态码 四、3xx 重定向1. 认识http重定向2.…

【javascript】isNaN(‘2-1‘)结果为什么是true

在JavaScript中&#xff0c;isNaN函数用于检查一个值是否为NaN&#xff08;非数字&#xff09;。当给定的值无法被解析为数字时&#xff0c;isNaN函数会返回true。 因此&#xff0c;使用isNaN(‘2-1’)进行判断时&#xff0c;2-1’是一个字符串&#xff0c;它包含一个减号&…

github ssh配置

1、生成公钥 用下面的命令生成公钥 ssh-keygen -t rsa -b 4096 -C 邮箱 生成的公钥默认在文件夹 ~/.ssh/ 下的 id_rsa.pub 2、在github配置本地的公钥 先复制本地公钥文件中的内容 cat ~/.ssh/id_rsa.pub 打开github的settings > SSH and GPG keys > new SSH key …

QT如何打包

目录 1.windeployqt工具 2.工具位置 3.使用方法 4.注意事项 Qt Creator 默认以动态链接的方式生成可执行文件&#xff0c;该文件无法独立运行&#xff0c;必须为其提供所需的动态链接库。也就是说&#xff0c;只分享 Qt Creator 生成的可执行文件是不行的&#xff0c;必须将…

nginx部署时http接口正常,ws接口404

可以这么配置 map $http_upgrade $connection_upgrade {default upgrade; close; }upstream wsbackend{server ip1:port1;server ip2:port2;keepalive 1000; }server {listen 20038;location /{ proxy_http_version 1.1;proxy_pass http://wsbackend;proxy_redirect off;proxy…

C语言,malloc使用规范

malloc 是 C 语言中用于分配内存的函数。它的名称是“memory allocation”的缩写。malloc 是在 <stdlib.h> 头文件中定义的。 malloc 的基本语法是&#xff1a; void* malloc(size_t size); 其中 size_t是要分配的字节数。如果分配成功&#xff0c;malloc返回一个指向分配…

什么是字体堆栈(font stack)?如何设置字体堆栈?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是字体堆栈&#xff08;Font Stack&#xff09;&#xff1f;⭐ 如何设置字体堆栈&#xff1f;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 …

【卷积神经网络】卷积,池化,全连接

随着计算机硬件的升级与性能的提高&#xff0c;运算量已不再是阻碍深度学习发展的难题。卷积神经网络&#xff08;Convolution Neural Network&#xff0c;CNN&#xff09;是深度学习中一项代表性的工作&#xff0c;CNN 是受人脑对图像的理解过程启发而提出的模型&#xff0c;其…