把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

来自 lmc 的树总结

膜拜 lmc 大神。
原链接

树的直径

直径:树上任意两节点之间最长的简单路径

求法有两遍 dfs 和 dp 等。

直径在某些题目中拥有极好的性质,例如直径上的某一点到其他点的最大值最小,即树的“中心”。

通常我们可以通过两次 dfs 将直径单独取出,将其子树的价值压到直径的对应点上,以此进行 dp 来满足题目的某些要求。

基环树

基环树:具有 n 个点 n 条边的连通图

关于基环树的问题主要可以看作树上多了一条边或将其缩成一个环,然后拆环成链考虑。同直径的求法一样,可以将子树贡献压到环上,然后再进行 dp 或其它操作。

有关基环树,直径的题目:[NOI2013] 快餐店

最近公共祖先(LCA)

两个节点的最近公共祖先,就是这两个点的公共祖先里面,离根最远的那个。

在树上问题的求解中经常需要求两个节点的 LCA,比如计算路径长度等。

快速求解 LCA 主要有以下几种解法:

  1. 倍增 LCA,单次查询时间复杂度为 O(logn),预处理复杂度为 O(nlogn),支持在线查询。

  2. tarjan LCA,单词查询时间复杂度为 O(1),预处理时间复杂度为 O(n),必须离线查询。

  3. 树剖 LCA,单次查询时间复杂度为 O(logn),预处理时间复杂度为 O(n),支持在线查询,在链上的单次查询时间复杂度可以到达 O(1)

  4. 欧拉序 RMQ 求 LCA,单次查询时间复杂度为 O(1),预处理时间复杂度为 O(nlogn),支持在线查询(但是这样写比较奇怪且容易挂,不推荐使用)。

……

表格:

单次查询时间复杂度 预处理时间复杂度 是否支持在线查询
倍增 O(logn) O(nlogn)
tarjan O(1) O(n)
树剖 O(logn) O(n)
欧拉序 O(1) O(nlogn)
……

还有很多奇怪的求解方式就不在一一介绍了,上面几种在大多数情况下都是可以使用的。

树的重心

对于树上的每一个点,计算其所有子树中最大的子树节点数,这个值最小的点就是这棵树的重心。

  1. 树的重心如果不唯一,则至多有两个,且这两个重心相邻。

  2. 以树的重心为根时,所有子树的大小都不超过整棵树大小的一半。

  3. 树中所有点到某个点的距离和中,到重心的距离和是最小的;如果有两个重心,那么到它们的距离和一样。

  4. 把两棵树通过一条边相连得到一棵新的树,那么新的树的重心在连接原来两棵树的重心的路径上。

  5. 在一棵树上添加或删除一个叶子,那么它的重心最多只移动一条边的距离。

重心还可以帮助实现点分治,点分树等。

dfs 序

dfs序中以某个点为根节点的子树可以表示为一个区间,这样可以将子树的修改转换为区间的修改。

通常 dfs 序与树状数组、线段树一同使用来满足树上带修改、查询的问题。

树上差分

树上差分的思路与数组上的差分类似,也是起点加上权值,终点减去,最后跑一遍前缀和。

树上差分需要用到 LCA 的求解,假设我们要将 u 到 v 的简单路径上所有的点加上一个权值 c,那么我们需要进行以下操作:

将 u、v 加上 c,将 LCA、fa[LCA] 减去 c。

单个操作的复杂度与 LCA 的时间复杂度相关,最后的树上前缀和时间复杂度为 O(n)

题目:[USACO15DEC] Max Flow P

利用树上差分、树状数组和 dfs 序,我们还可以实现树链上的修改:DFS 序 3,树上差分 1

树剖

虽然树剖不在 NOIP 里,但是思路简单,可以在没有想法的时候骗分甚至写出另类正解。

定义 重子节点 表示其子节点中子树最大的子结点。如果有多个子树最大的子结点,取其一。如果没有子节点,就无重子节点。

定义 轻子节点 表示剩余的所有子结点。

从这个结点到重子节点的边为 重边

到其他轻子节点的边为 轻边

若干条首尾衔接的重边构成 重链

把落单的结点也当作重链,那么整棵树就被剖分成若干条重链。

重链剖分有以下性质:

树上每个节点都属于且仅属于一条重链。重链开头的结点不一定是重子节点(因为重边是对于每一个结点都有定义的)。

所有的重链将整棵树 完全剖分

在剖分时 重边优先遍历,最后树的 dfs 序上,重链内的 dfs 序是连续的。按 dfn 排序后的序列即为剖分后的链。

一颗子树内的 dfs 序是连续的。

可以发现,当我们向下经过一条 轻边 时,所在子树的大小至少会除以二。

因此,对于树上的任意一条路径,把它拆分成从 LCA 分别向两边往下走,分别最多走 O(logn) 次,因此,树上的每条路径都可以被拆分成不超过 O(logn) 条重链。

也就是说无论重链还是子树内的 dfs 序都是连续的,这样我们就可以轻松地使用数据结构来维护子树以及路径上的修改和查询。

题目:[ZJOI2008] 树的统计

树上启发式合并(dsu on tree)

树上启发式合并就是在计算和传递子树的信息时,只保留重儿子的贡献,每次重新搜索轻儿子计算答案。

这样搜索一遍的时间复杂度可以证明是 O(nlogn) 的,dsu on tree 通常用于解决树上统计的问题。而且数组的下标为值,单次修改、查询的时间复杂度低的问题使用 dsu on tree 解决十分方便。

题目:Tree and Queries

一些其他树上问题的套路

对于统计一颗子树中的信息时,我们不仅可以利用 dsu on tree 解决,有时也可以使用树状数组解决。在进入这个节点时,减去当前的答案,更新完这个节点的子树后再加上此时的答案,这样就可以得到这棵子树的答案了。

题目:[USACO17JAN] Promotion Counting P

当有多次询问需要对树上的某些关键点进行答案统计,而关键点的数量之和又很少时,我们可以用建立虚树的方式统计答案,只保留关键点之间的祖孙关系进行计算。

题目:[SDOI2018] 战略游戏

posted @   djh0314  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
浏览器标题切换
浏览器标题切换end
点击右上角即可分享
微信分享提示