尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
树链剖分(树剖)算法详解:从原理到实现
1. 什么是树链剖分树链剖分Tree Chain Partition简称树剖是一种将树形结构转化为线性序列的算法技巧。它通过将树上的路径分解为若干条“重链”使得原本在树上难以高效处理的路径查询、路径修改等问题能够借助线段树、树状数组等数据结构在 O(log²n) 或 O(log n) 的时间复杂度内解决。树剖的核心思想是通过两次 DFS 预处理将树上的节点重新编号使得每条重链上的节点编号连续。这样树上的任意一条路径都可以被拆分成 O(log n) 段连续的区间从而可以用维护序列的数据结构来处理。2. 树链剖分的核心概念2.1 基本定义重儿子Heavy Son对于节点 u 的所有儿子中子树大小最大的那个儿子如果有多个任选一个。轻儿子Light Son除重儿子外的其他儿子。重边Heavy Edge连接节点与其重儿子的边。轻边Light Edge连接节点与其轻儿子的边。重链Heavy Chain由重边连续连接形成的极大路径。2.2 重要数组预处理结果fa[u]节点 u 的父节点。dep[u]节点 u 的深度根节点深度为 0 或 1。size[u]以 u 为根的子树大小。son[u]节点 u 的重儿子如果没有则为 0。top[u]节点 u 所在重链的顶端节点。dfn[u]节点 u 在 DFS 序中的新编号时间戳。rnk[dfn[u]]DFS 序编号对应的原节点即 rnk[dfn[u]] u。3. 树链剖分的预处理两次 DFS3.1 第一次 DFS计算父节点、深度、子树大小、重儿子void dfs1(int u, int father) { fa[u] father; dep[u] dep[father] 1; size[u] 1; son[u] 0; for (int v : g[u]) { if (v father) continue; dfs1(v, u); size[u] size[v]; if (size[v] size[son[u]]) { son[u] v; } } }3.2 第二次 DFS进行重链剖分分配 DFS 序int tim 0; void dfs2(int u, int tp) { top[u] tp; dfn[u] tim; rnk[tim] u; // 优先遍历重儿子保证重链上节点 DFS 序连续 if (son[u]) { dfs2(son[u], tp); } // 遍历轻儿子轻儿子自己作为新重链的顶端 for (int v : g[u]) { if (v fa[u] || v son[u]) continue; dfs2(v, v); } }4. 路径查询与修改树剖最经典的应用查询或修改树上两点 u, v 之间路径上的节点权值和或最大值等。核心操作不断将深度较大的点向上跳每次跳一整条重链并将这条重链对应的区间dfn[top[u]] 到 dfn[u]进行查询/修改。// 假设有线段树 seg 可以处理区间 [l, r] 的查询/修改 int query_path(int u, int v) { int res 0; while (top[u] ! top[v]) { if (dep[top[u]] dep[top[v]]) swap(u, v); // 处理 u 所在的重链区间 [dfn[top[u]], dfn[u]] res seg.query(1, 1, n, dfn[top[u]], dfn[u]); u fa[top[u]]; // 跳到上一条重链 } // 此时 u, v 在同一条重链上 if (dep[u] dep[v]) swap(u, v); res seg.query(1, 1, n, dfn[u], dfn[v]); return res; }5. 子树查询与修改由于 DFS 序的性质以 u 为根的子树中所有节点的新编号 dfn 是连续的区间 [dfn[u], dfn[u] size[u] - 1]。因此子树操作可以直接转化为区间操作// 查询子树 u 的权值和 int query_subtree(int u) { return seg.query(1, 1, n, dfn[u], dfn[u] size[u] - 1); } // 修改子树 u 中所有节点的权值加上 val void update_subtree(int u, int val) { seg.update(1, 1, n, dfn[u], dfn[u] size[u] - 1, val); }6. 时间复杂度分析预处理两次 DFSO(n)。路径操作每次跳转将当前节点 u 跳到 fa[top[u]]由于从叶子到根最多经过 O(log n) 条轻边每经过一条轻边子树大小至少翻倍因此路径会被拆分成 O(log n) 条重链区间。若区间操作线段树为 O(log n)则总复杂度为 O(log²n)。子树操作O(log n)线段树区间操作。7. 典型例题与代码模板例题给定一棵 n 个节点的树每个节点有一个权值。需要支持两种操作将节点 u 到节点 v 的路径上所有节点权值加上 val。查询节点 u 到节点 v 的路径上所有节点权值之和。完整代码模板较长此处给出核心结构#include bits/stdc.h using namespace std; const int N 1e5 5; vectorint g[N]; int fa[N], dep[N], size[N], son[N]; int top[N], dfn[N], rnk[N], tim; int w[N]; // 原权值 int nw[N]; // 按 DFS 序排列的权值 // 线段树部分略 struct SegTree { ... } seg; void dfs1(int u, int f) { ... } void dfs2(int u, int tp) { ... } void update_path(int u, int v, int val) { while (top[u] ! top[v]) { if (dep[top[u]] dep[top[v]]) swap(u, v); seg.update(1, 1, n, dfn[top[u]], dfn[u], val); u fa[top[u]]; } if (dep[u] dep[v]) swap(u, v); seg.update(1, 1, n, dfn[u], dfn[v], val); } int query_path(int u, int v) { int res 0; while (top[u] ! top[v]) { if (dep[top[u]] dep[top[v]]) swap(u, v); res seg.query(1, 1, n, dfn[top[u]], dfn[u]); u fa[top[u]]; } if (dep[u] dep[v]) swap(u, v); res seg.query(1, 1, n, dfn[u], dfn[v]); return res; } int main() { // 读入树 // 第一次 DFSdfs1(root, 0) // 第二次 DFSdfs2(root, root) // 将原权值 w[u] 按 DFS 序存入 nw[dfn[u]] // 建线段树 seg.build(1, 1, n, nw) // 处理询问 return 0; }8. 总结与扩展树链剖分的优势将树上路径问题转化为序列区间问题可以套用丰富的序列数据结构。预处理 O(n)单次路径操作 O(log²n)在大多数题目中足够高效。思想清晰模板性强学会后可以解决一大类树上路径问题。常见变体与应用边权转点权将边权赋给深度较大的端点查询时注意 LCA 处权值不计入。结合树状数组如果只有单点修改、区间查询可以用树状数组代替线段树。维护路径最值将线段树的求和改为求最大值/最小值。结合可持久化线段树实现树上路径第 k 大等查询。树链剖分是算法竞赛中处理树上路径问题的利器理解其“重链剖分区间维护”的核心思想后便能灵活应用于各种变式题目。
RELATED

相关推荐

AI生成内容检测工具与算法更新的技术博弈

AI生成内容检测工具与算法更新的技术博弈

1. 降AI工具与算法更新的速度博弈上周帮客户调试一个老牌降AI工具时,发现它对最新发布的Stable Diffusion 3模型支持度几乎为零。这已经是今年第三次遇到类似情况——当我在GitHub上提交issue时,开发者无奈回复:"算法更新太快&#xff0…

📅 2026/10/11 22:00:34
OpenClaw开源智能体网关:AI助手与即时通讯的完美融合

OpenClaw开源智能体网关:AI助手与即时通讯的完美融合

1. 项目概述:当AI助手遇上即时通讯上周在调试一个自动化工作流时,我突然意识到:如果能把AI助手直接集成到日常使用的聊天软件里,很多重复性工作就能在对话中一键完成。这个想法促使我找到了OpenClaw——一个开源的智能体网关项目&…

📅 2026/10/14 16:43:05
谷歌财报技术解析:云原生与AI驱动业绩增长及开发者机遇

谷歌财报技术解析:云原生与AI驱动业绩增长及开发者机遇

最近在分析科技公司财报时,发现谷歌母公司 Alphabet 2026 财年第二财季的业绩表现格外亮眼,归母净利润达到 1121.07 亿美元,同比增长 298%。作为开发者,我们不仅要关注技术本身,更要理解背后的商业逻辑和行业趋势。本文…

📅 2026/11/7 20:08:24
MORE NEWS

更多资讯

📰

工地太忙根本没时间复习考试?德国电工证办理流程保姆级教程来了

工地太忙根本没时间复习考试?德国电工证办理流程保姆级教程来了 工地太忙根本没时间复习考试?你是新乡转岗的特种作业从业者,正在考虑考取【德国电工证办理流程】,但面对复杂的流程和考试内容,心里没底?别急,这篇保姆级教程帮你一步步搞定德国电工证,…

📰

高压电工作业的视频2026河南最新政策下怎么考更靠谱

高压电工作业的视频2026河南最新政策下怎么考更靠谱 之前考的证在外省能不能转过来?这是很多在河南洛阳涧西区打工的老电工最关心的问题,尤其是像我这样在建筑工地上干了七八年的电工,手里拿着外地的高压电工作业证,却总担心在河南干项目时被卡住。现…

📰

电工证经贸委证怎么转异地 郑州报考避坑指南

电工证经贸委证怎么转异地 郑州报考避坑指南 学历不高怕报不上名?很多在郑州打工的电工朋友都遇到过这个问题。尤其是像我们信阳浉河区从事公路工程的,常常需要办理或更换电工证经贸委证,但因为学历问题,不少人心里打鼓,怕自己连报名资格都够不上。其实…

📰

宁养俊电工证多久拿证?怕考不过白交培训费的看这篇

宁养俊电工证多久拿证?怕考不过白交培训费的看这篇 怕考不过白交培训费?宁养俊电工证多久拿证?这是很多准备报考学员最关心的问题。特别是对于郑州金水区的朋友们,选择一家靠谱的培训机构,能大大降低考试失败的风险,也节省时间和金钱。这篇文章从真实学…

📰

宁养俊电工证真实经历:实操考试心里没底怕挂科?过来人教你稳过

宁养俊电工证真实经历:实操考试心里没底怕挂科?过来人教你稳过 实操考试心里没底怕挂科?这是我备考宁养俊电工证时最大的心理障碍。说实话,第一次听说这个证书的时候,我脑子里满是“考试难不难”“能不能一次通过”“挂科了怎么办”这些念头。作为鹤壁公…

📰

自贡哪里有办电工证多少钱 低学历也能考的实操攻略

自贡哪里有办电工证多少钱 低学历也能考的实操攻略 学历不高怕报不上名,但你真的了解电工证的含金量和报考门槛吗?在自贡,很多人都在问【自贡哪里有办电工证多少钱】,特别是那些没有高学历的打工者,总觉得这条路走不通。其实,电工证的报考要求并不像大…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬