线段树v2.0
前言
线段树,万金油数据结构。
线段树只会保留重要的、具有“代表性”的区间,来优化区间查询。
简介
下图(有点儿粗糙,请不要介意):
黑数字代表编号,红色的区间代表节点管辖的区间,至于绿色和黄色的 X 会在后面讲。
建树
Lemma 1:线段树至多有 层
我们从最下面开始看。
每往上一层,区间的数量大约会减半(实际上向下取整),要把节点数量减半到
在最坏情况下,每一层都会维护整个数组。所以直接对于整个数组暴力的复杂度也会是
但是,我们知道,线段树的核心,是拼,是凑啊!
Lemma 2:线段树有 个节点
每一个节点的作用其实就是把两个区间合并成一个,所以叶子节点有
所以,对于叶节点,我们直接把信息传上来;对于非叶子节点,我们用其两个儿子节点的信息合并。
区间查询
Lemma 3:对于一个区间,每层至多有 个节点所管辖的区间是这个区间的子区间,并且这个节点的父亲的区间不是这个区间的子区间(这是“终止节点”的定义)。
Lemma 3.1:对于一个终止节点,它的左/右边至少有一边的终止节点的深度比它低
反证。
如果两边的终止节点都比它高,那就违反了线段树的“二叉”的结构(无法解释这个终止节点到底“在哪儿”)。
证明了 Lemma 3.1 之后,就非常简单了:
还是反证。
如果有某一层有
-
有两个终止节点相邻,这违反了终止节点的定义;
-
没有两个终止节点相邻,这违反了 Lemma 3.1。
那怎么找终止节点?
直接搜索,搜到一个终止节点就返回。
区间修改
还记得前面提到的黄色 X 和绿色 X 吗(好像说反了)?这两个 X 就是实现快速区间修改的关键。
懒标记
仍然拿
然后,当我们访问到
如此往复,不要忘记更新信息。
当我们查询
往下搜到
我们下传
然后就可以安全的访问
永久标记
永久标记就是上面的黄 X,当我们访问到一个结点的时候我们不下传标记,而是把这个标记的贡献直接加进去。
注意修改时仍然要更新信息。
你可以把两种标记这样理解:
-
懒标记像是一个上司,他会在领导视察的时候清理账单,还清工资;
-
永久标记像是一个上司,但是他不会还清工资,而是伪造账单。
线段树分治
其实线段树分治的思想很简单,就是把某一个信息的所在区间当作一次区间修改,用永久标记的方式加入一棵在时间轴上建立的线段树。
当要回答某些时间点的信息的时候,我们一次性处理:
在线段树上 DFS,遇到了新信息就加入贡献,当回溯的时候撤销贡献。
就这么简单。
但由于贡献需要撤销,所以可能得使用可持久化数据结构。
可持久化线段树
好,现在我要保存线段树的历史版本。
所以我们需要可持久化线段树。
可持久化线段树只支持单点修改,但是仍然支持区间查询。
使用最经典的 Path Copying 思想,我们把修改的节点复制一份出来,然后就可以达到可持久化的目的了。
线段树能塞的各种奇奇怪怪的东西
线段树里面塞矩阵...还是 dp 矩阵
这个法子有个别名叫“动态 dp”。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具