树论

一、树的基础概念与性质

基本概念

  1. :无环连通图
  2. 节点的度:节点连接的边数
  3. 叶子节点:度为1的节点
  4. 子树:以某个节点为根的树的一部分
  5. 深度与高度:根节点深度为0(或1),叶子节点高度为0(或1)

树的存储

  1. 邻接表:最常用的存储方式
  2. 前向星:常用于竞赛
  3. 父节点数组:记录每个节点的父节点
  4. 儿子列表:记录每个节点的所有儿子

例题

  1. 树的遍历:给定一棵树,输出前序、中序、后序遍历序列
  2. 树的节点统计:统计树中节点的度、叶子节点数量等
  3. 树的构建:根据给定信息构建树(如根据父子关系)

二、树的遍历与序列

深度优先搜索(DFS)

  1. 前序遍历:根 → 左 → 右
  2. 后序遍历:左 → 右 → 根
  3. 中序遍历:左 → 根 → 右(仅对二叉树有意义)

广度优先搜索(BFS)

  1. 层序遍历:按层遍历树节点
  2. 求层数/深度:BFS天然记录层数

树的序列表示

  1. 欧拉序:DFS进入和离开节点都记录
  2. 括号序:类似欧拉序的表示方法
  3. DFS序:记录节点被访问的顺序

例题

  1. 树的直径:通过两次DFS/BFS求树的直径
  2. 树的重心:通过DFS求树的重心
  3. 子树求和:通过DFS序将子树转化为区间问题

三、树的直径与重心

树的直径

定义:树上最长简单路径的长度

性质

  1. 直径的两个端点一定是叶子节点
  2. 树中任意一点的最远点一定是直径的端点之一
  3. 所有直径一定经过树的重心(可能有多个)

求解方法

  1. 两次DFS/BFS:任选一点找到最远点,再从该点找到最远点
  2. 树形DP\(dp[u]\)表示以\(u\)为根的子树中最长路径长度

树的重心

定义:删除该节点后,最大连通块最小的节点

性质

  1. 重心可能在边上(两个节点),但通常指节点重心
  2. 树的重心最多有两个
  3. 以重心为根时,所有子树大小不超过\(\frac{n}{2}\)

求解方法

  1. DFS计算子树大小:同时计算删除该节点后的最大连通块大小
  2. 选择最大连通块最小的节点

例题

  1. 树的直径:求树的直径长度和直径路径
  2. 树的中心:求树上到所有节点距离之和最小的点
  3. 树网的核:在直径上选择一段路径,使得偏心距最小

四、最近公共祖先(LCA)

基本概念

定义:两个节点在树上的最近的公共祖先

求解方法

  1. 倍增法

    • 预处理每个节点的\(2^k\)级祖先
    • 查询时先将两个节点调整到同一深度
    • 然后同时向上跳
    • 时间复杂度:\(O(n \log n)\)预处理,\(O(\log n)\)查询
  2. 树链剖分

    • 将树剖分成链
    • 查询时在链上跳跃
    • 时间复杂度:\(O(n)\)预处理,\(O(\log n)\)查询
  3. Tarjan离线算法

    • 使用并查集
    • 在DFS过程中回答查询
    • 时间复杂度:\(O(n + q)\)
  4. RMQ+欧拉序

    • 将LCA转化为RMQ问题
    • 使用ST表或线段树解决

应用

  1. 树上两点距离\(dist(u, v) = depth[u] + depth[v] - 2 \times depth[lca(u, v)]\)
  2. 判断祖先关系:检查一个点是否是另一个点的祖先
  3. 树上路径:处理与树上路径相关的问题

例题

  1. 倍增法求LCA:模板题,给定树和查询,求每对节点的LCA
  2. 树上距离:多次查询树上两点距离
  3. 树上路径点权之和:查询树上两点路径上所有点的权值之和

五、树上差分

点差分

操作:对路径\((u, v)\)上所有点的权值加\(k\)

方法

  1. \(diff[u] += k\)
  2. \(diff[v] += k\)
  3. \(diff[lca(u, v)] -= k\)
  4. \(diff[father(lca(u, v))] -= k\)

边差分

操作:对路径\((u, v)\)上所有边的权值加\(k\)

方法

  1. \(diff[u] += k\)
  2. \(diff[v] += k\)
  3. \(diff[lca(u, v)] -= 2k\)

例题

  1. 运输计划:选择一条边变为0,使得所有运输路径的最大值最小
  2. 天天爱跑步:每个点有一个观察时间,求每个点能看到多少玩家
  3. 雨天的尾巴:对树上路径的所有点发放不同种类的救济粮,求每个节点最多的救济粮种类

六、树形动态规划

基本类型

  1. 普通树形DP:在树上进行DP,通常后序遍历
  2. 树上背包:在树上进行分组背包或依赖背包
  3. 换根DP:通过两次DFS,计算以每个节点为根时的信息

常见模型

  1. 节点选择问题:选择一些节点,满足某些约束,最大化/最小化权值和
  2. 树上路径问题:求满足条件的路径数量或权值
  3. 子树统计问题:统计子树中满足条件的节点或路径

状态设计技巧

  1. \(dp[u][0/1]\):表示选或不选节点\(u\)
  2. \(dp[u][j]\):表示以\(u\)为根的子树中,选择\(j\)个节点的最优解
  3. \(dp[u]\):表示以\(u\)为根的子树的最优解

例题

  1. 没有上司的舞会:选择一些节点,使得没有直接上下级关系,最大化权值和
  2. 二叉苹果树:保留\(Q\)条边,使得苹果数最多
  3. 战略游戏:选择最少的士兵覆盖所有边
  4. 计算机:求每个节点到其他节点的最远距离

七、树链剖分

基本概念

树链剖分:将树划分成若干条链,使得树上的操作可以转化为序列上的操作

常用术语

  1. 重儿子:子树大小最大的儿子
  2. 轻儿子:非重儿子的儿子
  3. 重链:由重儿子连接形成的链
  4. 轻边:连接两个不同重链的边

剖分过程

  1. 第一次DFS:计算子树大小、深度、父节点、重儿子
  2. 第二次DFS:分配DFS序,连接重链

应用

  1. 路径修改/查询:将路径拆分成\(O(\log n)\)条链
  2. 子树修改/查询:子树对应DFS序上的连续区间
  3. LCA查询:通过跳重链快速求LCA

例题

  1. 树链剖分模板:路径修改、路径查询、子树修改、子树查询
  2. 树上操作:支持多种操作(加、乘、赋值)的树链剖分
  3. 染色:路径染色,查询路径上颜色段数量

八、树上启发式合并

基本思想

启发式合并:将小子树的信息合并到大子树中,减少时间复杂度

时间复杂度

  • 每个节点被合并的次数为\(O(\log n)\)
  • 总时间复杂度为\(O(n \log n)\)

算法流程

  1. 先遍历轻儿子,计算答案但不保留信息
  2. 再遍历重儿子,计算答案并保留信息
  3. 最后遍历轻儿子,将信息合并到重儿子中

应用场景

  1. 子树颜色统计:统计每个子树中不同颜色的数量
  2. 子树众数:求每个子树中出现次数最多的颜色
  3. 子树查询:离线回答子树相关的查询

例题

  1. 树上数颜色:求每个子树中不同颜色的数量
  2. Lomsat gelral:对于每个子树,求出现次数最多的颜色编号和
  3. Tree and Queries:查询子树中出现次数≥\(k\)的颜色数量

九、基环树

基本概念

基环树:在树的基础上增加一条边,形成恰好一个环

性质

  1. \(n\)个节点,\(n\)条边
  2. 有且仅有一个环
  3. 去掉环上任意一条边就变成一棵树

处理方法

  1. 找环:使用DFS或拓扑排序找到环
  2. 破环成树:删除环上一条边,转化为树问题
  3. 环上DP:在环上进行动态规划

常见问题

  1. 基环树直径:可能经过环或不经过环
  2. 基环树DP:类似于没有上司的舞会,但需要处理环
  3. 基环树最短路:环上路径的选择

例题

  1. 岛屿:求基环树森林中每棵基环树的直径之和
  2. 骑士:基环树上的最大权独立集
  3. 旅行:在基环树上找字典序最小的DFS序

十、树的计数与生成树

树的计数

  1. Cayley公式\(n\)个节点的无标号树有\(n^{n-2}\)
  2. Prüfer序列:建立树与序列的一一对应
  3. 有根树计数:考虑根节点的选择

生成树

  1. 最小生成树
    • Kruskal算法
    • Prim算法
  2. 次小生成树:枚举不在最小生成树中的边
  3. 最小生成树计数:使用Matrix-Tree定理

树哈希

用途:判断两棵树是否同构

方法

  1. 有根树哈希:递归计算子树哈希值
  2. 无根树哈希:以重心为根进行哈希
  3. 常用哈希函数\(hash(u) = 1 + \sum hash(v) \times prime(size(v))\)

例题

  1. 树的同构:判断多棵树是否同构
  2. 最小生成树计数:求最小生成树的数量
  3. 严格次小生成树:求权值和严格大于最小生成树的生成树
  4. Prüfer序列:实现树与Prüfer序列的相互转换

十一、其他树相关问题

虚树

应用场景:处理树上多次询问,每次询问只涉及少量关键节点

构建方法

  1. 将关键节点按DFS序排序
  2. 使用栈维护右链
  3. 依次插入节点,维护LCA

点分治

应用场景:处理树上路径统计问题

算法流程

  1. 找到当前子树的重心
  2. 计算经过重心的路径
  3. 递归处理子树

边分治

类似于点分治,但每次选择一条边将树分成两部分

笛卡尔树

定义:满足堆性质的二叉搜索树

应用

  1. 区间最值查询
  2. 直方图最大矩形

例题

  1. 消耗战:虚树模板题,多次询问切断关键点到根的最小代价
  2. 树点涂色:点分治处理路径颜色问题
  3. 重建计划:点分治+单调队列求长度在\([L, R]\)之间的最大权路径

总结

树论是OI竞赛中的重要部分,涵盖了基础遍历、高级数据结构、动态规划、图论等多个方面。掌握树论需要:

  1. 理解基础概念:树的遍历、性质、序列表示
  2. 掌握核心算法:LCA、树形DP、树链剖分、树上启发式合并
  3. 熟练应用技巧:树上差分、点分治、虚树
  4. 解决经典问题:树的直径、重心、基环树、生成树

建议的学习路径:

  1. 从基础遍历和DFS序开始
  2. 学习LCA和树上差分
  3. 掌握树形DP和树链剖分
  4. 学习高级技巧如点分治、虚树
  5. 大量练习,积累经验

每个算法都有其适用场景,需要根据具体问题选择合适的方法。在比赛中,树论问题往往综合多个知识点,需要灵活运用所学知识。

posted @ 2026-01-12 10:56  Chestify  阅读(11)  评论(0)    收藏  举报