可持久化线段树 2

推荐在 cnblogs 上阅读。

可持久化线段树

前言

这个东西之前讲过,但是用得少,很快就忘了。

我又看了我之前的那篇笔记,简直就是胡言乱语。所了解的太浅了。

最近在刷数据结构,于是决定再写一篇。

但是,之前那篇不打算删了,想看黑历史的可以去看。

算法概要

可持久——即可以保存历史版本。

我们如何得到一棵可以保存历史数据的树呢?最笨的方法就是每个操作之后都建一棵线段树。

如何优化?

发现我们可以共用前面建好的结构,无需重新建树。

主席树

主席树是可持久化线段树的一种,由黄嘉泰发明,因名字缩写而被称为主席树。

主席树一开始是用来处理区间第 k k k 小的问题。

一句话概要思想:一棵权值线段树是由不在同一层的从根到叶子结点的链构成。

什么意思呢?

可以理解成一条时间轴将根节点穿起来,每个根节点都是一个历史版本的入口,每个历史版本都可以沿用以前的节点结构。

实现主席树——建树

难点其实就是建树,因为这与主席树的思想紧紧相关。

每次插入一个信息,就将它从根节点到叶子结点的这条链新建出来(权值线段树)。

当然,这条链上的节点都是新建,因为这是一个新的历史版本;其他节点就沿用以前的节点。

例 1 区间第 k k k

P3834 【模板】可持久化线段树 2

怎么做呢?

我们可以按顺序插入数组中的每个元素。

这样的话就有 n n n 个历史版本。

当我们想知道 [ l , r ] [l,r] [l,r] 的第 k k k 小时,我们可以只关注版本 l − 1 l-1 l1 和版本 r r r

这样的话,又因为这是棵权值线段树,所以可以通过当前节点的 s i z e size size 之差来判断第 k k k 小在什么地方。

注意,本题不带修。

带修怎么办呢?看例 3。

code

#include<bits/stdc++.h>
using namespace std;#define int long longconst int MAXN=2e5+5,INF=1e9;int n,m,tot;
int a[MAXN];
int rts[MAXN];
struct TREE
{int lc,rc,sz;
}tr[MAXN<<5];void pushup(int rt)
{tr[rt].sz=tr[tr[rt].lc].sz+tr[tr[rt].rc].sz;
}void update(int &rt,int lst,int l,int r,int val)
{rt=++tot;tr[rt]=tr[lst];if(l==r)tr[rt].sz++;else{int mid=(l+r)>>1;if(val<=mid)update(tr[rt].lc,tr[lst].lc,l,mid,val);elseupdate(tr[rt].rc,tr[lst].rc,mid+1,r,val);pushup(rt);}
}int query(int r1,int r2,int l,int r,int k)
{if(l==r)return l;int lc1=tr[r1].lc,lc2=tr[r2].lc;int mid=(l+r)>>1;int tmp=tr[lc2].sz-tr[lc1].sz;if(tmp>=k)return query(lc1,lc2,l,mid,k);return query(tr[r1].rc,tr[r2].rc,mid+1,r,k-tmp);
}signed main()
{scanf("%lld%lld",&n,&m);for(int i=1;i<=n;i++){scanf("%lld",&a[i]);update(rts[i],rts[i-1],-INF,INF,a[i]);}for(int i=1;i<=m;i++){int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);printf("%lld\n",query(rts[x-1],rts[y],-INF,INF,z));}return 0;
}

例 2 可持续化数组

P3919 【模板】可持久化线段树 1(可持久化数组)

这个就是很简单的了,不用权值线段树。

首先对于原数组建线段树,称为历史版本 0。

然后对于 m m m 次操作,每次都是一个历史版本;如果是查询操作,就复制前一个一模一样的。

剩下的就是中规中矩了,就是建一条链,其他节点就沿用。

code

#include<bits/stdc++.h>
using namespace std;// #define int long long
#define ls tr[rt].lc
#define rs tr[rt].rcconst int MAXN=2e6+5;int n,m;
int a[MAXN],rts[MAXN*20];
struct HJT
{int lc,rc,val;
}tr[MAXN*20];
int tot;void build(int &rt,int l,int r)
{rt=++tot;if(l==r)return tr[rt].val=a[l],void();int mid=l+r>>1;build(ls,l,mid);build(rs,mid+1,r);
}void update(int &rt,int old,int l,int r,int x,int k)
{rt=++tot;tr[rt]=tr[old];if(l==r)return tr[rt].val=k,void();int mid=l+r>>1;if(x<=mid) update(ls,tr[old].lc,l,mid,x,k);else update(rs,tr[old].rc,mid+1,r,x,k);
}int query(int rt,int l,int r,int x)
{if(l==r)return tr[rt].val;int mid=l+r>>1;if(x<=mid) return query(ls,l,mid,x);return query(rs,mid+1,r,x);
}signed main()
{scanf("%d%d",&n,&m);for(int i=1;i<=n;i++) scanf("%d",&a[i]);build(rts[0],1,n);for(int i=1,old,op,x,k;i<=m;i++){scanf("%d%d%d",&old,&op,&x);if(op==1){scanf("%d",&k);update(rts[i],rts[old],1,n,x,k);}elseprintf("%d\n",query(rts[i]=rts[old],1,n,x));}return 0;
}

例 3 区间第 k k k 小(带修)

首先你要知道树状数组是个什么东西。

这里要用到它的思想。

题面

给定一个长度为 n n n n ≤ 50 , 000 n \leq 50,000 n50,000)的数组 a 1 , a 2 . . . , a n a_1 , a_2 ... ,a_n a1,a2...,an q q q q ≤ 10 , 000 q \leq 10,000 q10,000)此询问,每次询问:

  1. Q i j k 表示区间 [ i , j ] [i,j] [i,j] 中第 k k k 小的数是多少,并输出这个数
  2. C i t 表示将第 i i i 个数改为 t t t

Solution

首先考虑最笨的办法,就是修改这个历史版本后,它后面的所有版本都跟着改写。

怎么优化呢?

想起树状数组就是通过类树分区间管辖,所以可以做到 O ( log ⁡ n ) O(\log n) O(logn)

那这里也可以沿用这种思想,就是分区间管辖,每次改写就改写管辖他们的“大哥”,查询的时候在下放。

概要就是这么个概要,洛谷上没有这道题,我也不打算写代码(看起来很麻烦的样子),自己去写吧(雾)。

参考文献

  • [1] zcysky,《题解 P3919 【【模板】可持久化数组(可持久化线段树/平衡树)】》

结尾

先草草结束吧,可能未来还会写可持久化平衡树什么的,也不确保这次一定就完全掌握了主席树。

先这样吧,多卷题,时而温故而知新。

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

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

相关文章

一种简易的多进程文件读写器

目录 1. 前言2. 初步实现3. ParallelFileProcessor 1. 前言 在数据清洗场景下&#xff0c;我们可能需要对一个 .jsonl 文件清洗以得到另一个 .jsonl 文件。一种直观的做法就是逐行读取&#xff0c;逐行清洗&#xff0c;然后逐行写入&#xff0c;这一流程的示意图如下&#xff…

【wails】(6):使用wails做桌面应用开发,使用gin+go-chatglm.cpp进行本地模型运行,在windows上运行成功

1&#xff0c;整体架构说明 主要使用&#xff0c;参考的开源项目是&#xff1a; https://github.com/wailsapp/wails 前端项目&#xff1a; https://github.com/Chanzhaoyu/chatgpt-web 运行模型&#xff1a; https://github.com/Weaxs/go-chatglm.cpp 参考代码&#xff1a; h…

深度神经网络中的计算和内存带宽

深度神经网络中的计算和内存带宽 文章目录 深度神经网络中的计算和内存带宽来源原理介绍分析1&#xff1a;线性层分析2&#xff1a;卷积层分析3&#xff1a;循环层总结 来源 相关知识来源于这里。 原理介绍 Memory bandwidth and data re-use in deep neural network computat…

五.AV Foundation 视频播放 - 标题和字幕

引言 本篇博客主要介绍使用AV Foundation加载视频资源的时候&#xff0c;如何获取视频标题&#xff0c;获取字幕并让其显示到播放界面。 设置标题 资源标题的元数据内容&#xff0c;我们需要从资源的commonMetadata中获取&#xff0c;在加载AVPlayerItem的时候我们已经指定了…

Sentinel微服务流量治理组件实战上

目录 分布式系统遇到的问题 解决方案 Sentinel 是什么&#xff1f; Sentinel 工作原理 Sentinel 功能和设计理念 流量控制 熔断降级 Sentinel工作主流程 Sentinel快速开始 Sentinel资源保护的方式 基于API实现 SentinelResource注解实现 Spring Cloud Alibaba整合…

AIGC 架构:RAG (retrieval augumented generation) 应用可以使用 PostgreSQL 作为向量数据库组件吗?

是的&#xff0c;RAG&#xff08;检索增强生成&#xff09;应用程序可以绝对地使用 PostgreSQL 作为向量数据库&#xff01;事实上&#xff0c;它是一个流行的选择&#xff0c;因为有以下几个优点&#xff1a; 使用 PostgreSQL 和 pgvector 的优点&#xff1a; 集成解决方案&…

【颠覆旧知识】JS的原型链搜索原则;

最近准备面试&#xff0c;梳理以前的知识&#xff0c;发现我以前对原型链的搜索原则理解一直不完全对。 以前的理解&#xff1a; “在当前对象未找到该属性&#xff0c;就一直向上查找&#xff0c;找到就停止并返回该数据&#xff0c;如果直到object的原型也没找到&#xff0c…

介绍 PIL+IPython.display+mtcnn for 音视频读取、标注

1. nn.NLLLoss是如何计算误差的? nn.NLLLoss是负对数似然损失函数&#xff0c;用于多分类问题中。它的计算方式如下&#xff1a;首先&#xff0c;对于每个样本&#xff0c;我们需要将其预测结果通过softmax函数转换为概率分布。softmax函数可以将一个向量映射为一个概率分布&…

第四节:Vben Admin登录对接后端getUserInfo接口

系列文章目录 第一节&#xff1a;Vben Admin介绍和初次运行 第二节&#xff1a;Vben Admin 登录逻辑梳理和对接后端准备 第三节&#xff1a;Vben Admin登录对接后端login接口 第四节&#xff1a;Vben Admin登录对接后端getUserInfo接口 文章目录 系列文章目录前言一、回顾Vben…

RK3568平台 阻塞IO和非阻塞IO

一.IO 模型的分类 IO 模型根据实现的功能可以划分为为阻塞 IO、非阻塞 IO、信号驱动IO&#xff0c;IO多路复用和异步 IO。根据等待 IO 的执行结果进行划分&#xff0c;前四个 IO 模型又被称为同步IO. 同步IO与异步IO&#xff1a; 以现实生活去餐馆吃饭为例&#xff0c;根据菜…

Alibaba分布式事务组件Seata实战

Alibaba分布式事务组件Seata实战 事务 本地事务 对于操作单一数据库的场景下的事务&#xff0c;ACIO特性是数据库直接支持的 分布式事务 在分布式情况下&#xff0c;需要的操作资源分布在多个资源服务上&#xff0c;而应用需要保证对于多个资源服务器的数据操作要么全部成…

Linux——缓冲区封装系统文件操作

&#x1f4d8;北尘_&#xff1a;个人主页 &#x1f30e;个人专栏:《Linux操作系统》《经典算法试题 》《C》 《数据结构与算法》 ☀️走在路上&#xff0c;不忘来时的初心 文章目录 一、FILE二、封装系统接口实现文件操作1、text.c2、mystdio.c3、mystdio.h 一、FILE 因为IO相…

Typora结合PicGo + 使用Github搭建个人免费图床

文章目录 一、国内图床比较二、使用Github搭建图床三、PicGo整合Github图床1、下载并安装PicGo2、设置图床3、整合jsDelivr具体配置介绍 4、测试5、附录 四、Typora整合PicGo实现自动上传 每次写博客时&#xff0c;我都会习惯在Typora写好&#xff0c;然后再复制粘贴到对应的网…

基于springboot+vue的校园社团信息管理系统(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

自定义搭建管理系统

最近使用自己搭建的脚手架写了一个简易管理系统&#xff0c;使用webpackreactantd&#xff0c;搭建脚手架参考&#xff1a; 使用Webpack5搭建项目&#xff08;react篇&#xff09;_babel-preset-react-app-CSDN博客 搭建的思路&#xff1a; 1. 基建布局&#xff0c;使用antd的…

代码随想录算法训练营第二十五天 | 216.组合总和III,17.电话号码的字母组合 [回溯篇]

代码随想录算法训练营第二十五天 LeetCode 216.组合总和III题目描述思路参考代码总结 LeetCode 17.电话号码的字母组合题目描述思路参考代码 LeetCode 216.组合总和III 题目链接&#xff1a;216.组合总和III 文章讲解&#xff1a;代码随想录#216.组合总和III 视频讲解&#xff…

Java零基础 - 字符串连接运算符

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一个人虽可以走的更快&#xff0c;但一群人可以走的更远。 我是一名后…

linux ubuntu 开发环境搭建 opencv fftw openvino

OpenCV 下载 opencv 源码&#xff1a;Releases - OpenCV 官方安装文档&#xff1a;https://docs.opencv.org/4.x/d7/d9f/tutorial_linux_install.html 详细的安装过程可以参考文章&#xff1a; 在 Linux 系统中编译安装 OpenCV - 知乎 安装依赖项&#xff1a; sudo apt-get …

ubuntu 22 安装 python3.11.7

ubuntu升级python到python3.11&#xff08;可能是全网最靠谱的方法&#xff0c;亲测有效&#xff09;_ubuntu python3.11-CSDN博客 在 Ubuntu 中升级 Python 到 3.11 版本可以通过编译源代码或者使用第三方工具来完成。请注意&#xff0c;在升级 Python 之前&#xff0c;请确保…

采用遗传算法搜索MAC效率最高的矩阵乘规模

如何采用遗传算法搜索MAC效率最高的矩阵乘规模 具体实现MAC效率评估代码(eval.py)遗传算法实现 本文介绍了采用遗传算法搜索MAC效率最高的矩阵乘规模 需求背景: 一些AI加速卡在做矩阵乘时,因硬件或软件的约束,并不是规模越大MAC效率越高在测试AI加卡的实际算力时,采用MAC效率最…