树上问题相关
1|0基本定义与前置知识
-
树的 dfs 序:我们称对一棵树
进行深度优先搜索后得到的节点序列为树的 dfs 序。称 表示 号点在 dfs 序中的位置。 -
我们称
为 在树中的父节点, 表示 的深度(一般的,这里的深度定义为经过的点数)。 -
我们称
为 子树内的所有点, 表示 的所有儿子节点。 -
我们称
表示 的距离, 为 在树上的最近公共祖先。
2|0最近公共祖先问题相关
2|1求解最近公共祖先
倍增
倍增是最基本的求解最近公共祖先的方法,其复杂度为
考虑如何暴力求解一对点
倍增求解最近公共祖先优点是可以支持增加叶节点且实现相对简单,缺点是一般来说常数相对较大,且结构稳定,不灵活。
树链剖分
树链剖分也是求解最近公共祖先的一种方式,复杂度为
树链剖分求解的过程是每次从
树剖求解最近公共祖先的优势在于其常数相对倍增较小,且可以搭配需要支持树链剖分的题目使用。
dfs 序和欧拉序
由于 dfs 序求解最近公共祖先在代码难度和常数方面均吊打欧拉序,所以本文只介绍前者。
dfs 序求解最近公共祖先可以做到
我们首先求出任意一组 dfs 序。注意到一个性质,对于一对点
skip2004 给出了更简洁的写法。具体而言,我们令查询区间变为
LNOI2014 LCA
这种求解最近公共祖先的算法只是一种思想,单纯求解没有实用价值。
考虑求解
2|2最近公共祖先相关应用
一般应用于路径问题。对于统计全部路径信息的题目,可以考虑将路径在其最近公共祖先处统计答案。
最近公共祖先还有一些奇怪的结论,我们将其放在下面。
-
对于两条链
,其路径交 不为直链当且仅当 。 -
对于两条链
,若其有交,则其两交点为 中最深的两个,令其为 ,且两条路径有交当且仅当 或 。正确性证明可以见 panyf 的博客。
2|3例题
快递
给 ducati 大跌磕头了/kt。考虑将相交路径分为直链和非直链考虑。
先考虑交成一个直链的部分。首先将给定的路径中的非直链变成两条直链。考虑把每对路径的贡献放在其下交点上计算。对于一个固定的点,考虑所有从子树向上延伸到它的路径,显然在这个点上可能贡献到答案的路径对只有向上延伸的最长的和次长的。因此直接维护最长和次长路径分别是哪条,然后自底向上转移即可。
然后考虑非直链。应用上面的结论,我们把路径
3|0重构树相关
这里的重构树主要指 Kruskal 重构树。下文中我们主要讨论最小生成树意义下的 Kruskal 重构树。
3|1算法流程
对于一棵有边权树
令树的边集为
3|2性质
-
性质 1:在不考虑叶节点的情况下,Kruskal 重构树满足堆性质。
由于按照边权排序,故每个虚点的权值一定严格大于其子节点的点权。
-
性质 2:对于每个节点,其在原树上经过边权不超过
的边能到达的点集等价于在 Kruskal 重构树上其祖先节点中点权不大于 且深度最浅的点的子树中的叶节点集合。由性质 1 可以简单推出。这也是 Kruskal 重构树的核心性质。
其实有时我们可以不显示建出 Kruskal 重构树,而是利用 Kruskal 重构树的思想,扫描每一条边,把某些类似于限制“只经过边权不小于
3|3例题
樱符
非常坏题目,恨来自中国。
首先考虑树上版本的问题怎么做。注意到此时最大流的限制就是相当于经过边权不小于最大流的边能否到达某个点,因此倒序扫描每一条边,然后维护并查集,每次合并两个连通块时考虑计算答案。注意到当前边一定是限制最大流的那条边,所以
然后考虑放到仙人掌上。不妨先强化一下这个问题,对于一般图,我们的做法是建出最小割树,然后跑上面的做法。而仙人掌可以模拟这一过程。具体而言,对于仙人掌上的每一个简单环,我们找出边权最小的边,将其断开,并给其它边加上这条边的权值,得到的树
小 ω 的树
依然考虑上面那个题的做法,我们要求子图内边的最小值这样的东西,因此我们不妨枚举这个最小值。注意到在边的最小值确定以后,点一定是越选多越好,那么假设当前扫描的边权为
4|0虚树
一般适用于复杂度和点个数相关的问题。在此之前,有必要先介绍虚树的定义及其构造过程。
4|1虚树的定义及算法流程
给定一棵树
。 , 。- 在此基础上,最小化
。
其中,
我们有两种方法构建虚树。其中一种较为难写且复杂度和精细实现的另一种几乎只有常数差别,所以我们只介绍后者。
首先介绍算法流程。我们维护一个点的序列
然后我们按照在原树上的 dfs 序将
下面给出做法的正确性证明。我们首先考虑为什么构建的点集是正确的。考虑对于一个点
注意到如果使用上文中介绍的
4|2性质
由虚树的构建过程可知,
4|3例题
快递
可见上文最近公共祖先问题相关的例题部分。
awa
这个好(赞赏)。
对于一种颜色
考虑如何求出所有的支配三元组。对于每一种颜色建立虚树,处理出来虚树上每个点的支配点。那么对于一条虚边,相当于是从其代表的祖先后代链中的某一个节点裂开,一半给上面的点支配,一半给下面的支配。根据上述过程不难发现,支配三元组的个数是
然后考虑点分治。把询问点挂到点分树上所在节点到根的每一个点上。然后如果按照 dfn 序和距离分治中心两维作为二维平面的话,修改相当于平面矩形加,查询相当于单点查。因此对于每一个分治中心做扫描线即可。时间复杂度
5|0点分治
点分治适合处理树上邻域问题。此前有必要先引入点分治算法流程。
5|1算法流程
点分治和序列上的分治有相似性,后者是考虑跨过区间中点的区间信息,前者是考虑跨过分治中心的路径信息。
首先回忆在序列上分治我们是怎么做的,每次选择一个分治点,以和问题规模相关的复杂度处理出其到分治点的信息,然后统计跨过分治点的答案,最后向分治点两侧递归。一般的,问题规模是分治区间的长度,而分治点取区间终点,这样分治层数只有
现在考虑将其搬到树上,我们希望找到一个分治点的决策,使得其也会恰好分治
5|2性质与应用
-
每轮点分治过程中当前分治到的点集在原树上都是一个连通块。
考虑点分治的算法流程,每次对连通块内选重心,删掉后向新形成的连通块递归,故容易得到如上结论。
-
点分治的连通块大小和是
的。原因是点分治共分治
层,每层大小为 。这也保证了点分治复杂度的正确性。
基于上述性质,我们可以构建出点分树。具体而言,将每一层的分治中心和上一层的分治中心连边。点分树有重要性质为树高为
点分治一般的坑点在于子树内信息的去重。一般可以对统计答案操作加上一个操作类型
5|3例题
路径大小差
军队
awa
可见上文虚树相关部分。
6|0链剖分
__EOF__

本文链接:https://www.cnblogs.com/-Complex-/p/17781212.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话