树论-树链剖分
树链剖分是一种用于处理树上路径查询的算法,它将树分解为多条链,使得任意两点间的路径可以表示为若干段链的组合。
树链剖分分为 重链剖分 和 长链剖分 。
重链剖分
定义
重儿子:其儿子中子树大小最大的儿子。如有多个子树大小最大的儿子,只取一个儿子作为重儿子。
轻儿子:其儿子中不是重儿子的儿子。
重边:重儿子与其父亲的边
轻边:轻儿子与其父亲的边
重链:许多条首尾相接的重边
过程
\(f_x\) : \(x\) 的父亲
\(dep_x\) : \(x\) 的深度
\(si_x\) : 以 \(x\) 为根的子树大小
\(son_x\) : \(x\) 的重儿子
第一次dfs处理出来以上信息
\(dfn_x\) : \(x\) 的dfs序
\(idfn_x\) : dfs序为 \(x\) 的节点编号
\(top_x\) : \(x\) 所在的重链的顶部节点(深度最小的点)
第二次dfs处理出来以上信息
代码
第一次dfs
1 2 3 4 5 6 7 8 9 10 |
|
第二次dfs
1 2 3 4 5 6 7 8 9 |
|
性质
1.一棵子树内的dfs序是连续的。
2.整棵树的根节点到树内任意一点的路径可以被拆分成不超过 \(O(\log n)\) 条重链。
3.重链上的dfs序是连续的。
应用
维护LCA(最近公共祖先)
两个点不断向上跳重链,当两个点跳到同一条重链上时,深度较小的点为LCA。
代码
1 2 3 4 5 6 7 |
|
维护点权信息
维护子树的信息
根据性质1可知,任意一棵子树内的dfs序是连续的,设 \(x\) 为这棵子树的根,那么 \(dfn_x\) 到 \(dfn_x+si_x-1\) 这段区间就是子树所有节点的dfs序。
可以利用数据结构来维护区间信息。
维护路径的信息
可以把这条路径 \((x,y)\) 拆开,拆成路径 \((lca(x,y),x)\) 与路径 \((lca(x,y),y)\) 。
也就是这两个点不断向上跳重链,根据性质3可知,重链上的dfs序是连续的,跳重链的过程可以转化成区间问题。
当两个点跳到同一个重链上时,根据性质3可知,在同一个重链上时可以转化成区间问题。
可以利用数据结构来维护区间信息。
代码
1 2 3 4 5 6 7 8 9 10 11 |
|
维护边权信息
每个节点的父亲只有一个,所以将父亲到儿子的边权下放到儿子上成为儿子的点权。
根据性质-dfs序是连续的,那么将上面的维护点权信息更改一下就行了。
例题
P3379 【模板】最近公共祖先(LCA)
方法之一:树剖lca
P3384 【模板】重链剖分/树链剖分
模版
题单
P7746 [COCI2011-2012#3] PLAĆE
点权板子
P3038 [USACO11DEC] Grass Planting G
边权板子
P2146 [NOI2015] 软件包管理器
点权板子
P3833 [SHOI2012] 魔法树
点权板子
P4114 Qtree1
边权板子
P2590 [ZJOI2008] 树的统计
点权板子
P4315 月下“毛景树”
点权板子
P3178 [HAOI2015] 树上操作
点权板子
P1505 [国家集训队] 旅游
线段树维护边权
P4116 Qtree3
线段树维护最小dfs序
P4092 [HEOI2016/TJOI2016] 树
线段树维护最大dfs序
P2486 [SDOI2011] 染色
线段树维护区间两个端点颜色以及区间颜色段数。
合并区间时注意贡献。
统计答案时注意贡献。
长链剖分
定义
重儿子:其儿子中子树深度最大的儿子。如有多个子树深度最大的儿子,只取一个儿子作为重儿子。
轻儿子:其儿子中不是重儿子的儿子。
重边:重儿子与其父亲的边
轻边:轻儿子与其父亲的边
重链:许多条首尾相接的重边
性质
1.任意一点 \(x\) 的 \(k\) 级祖先 \(y\) 所在的长链长度大于等于 \(k\) 。
2.整棵树的根节点到树内任意一点的路径可以被拆分成不超过 \(O(\sqrt n)\) 条重链。
应用
维护树上 K 级祖先(LA)
时间复杂度为 \(O(n \log n)\) — \(O(1)\) 。
预处理
1.每个点所在链的顶点和深度
2.利用树上倍增预处理出每个点的 \(2^n\) 级祖先。
3.对于每条链,其长度为 \(len\) ,预处理出这条链的顶点向上的 \(len\) 个祖先和向下的 \(len\) 个儿子。
4.预处理出 \(1\) 到 \(n\) 在二进制下的最高位 \(g_i\) 。
查询
1.将询问的节点 \(x\) 跳到 \(x\) 的 \(2^{g_i}\) 级祖先。
2.剩下还有 \(k-2^{g_i}\) 级,可以发现 \(k-2^{g_i}<2^{g_i}\) ,因为此时 \(x\) 所在的长链长度一定 \(\geq2^{g_i}\) ,那么此时 \(x\) 可以先跳到 \(x\) 所在链的顶点。
3.如果还没跳到,那么可以用预处理3中的数组继续向上跳;如果跳过去了,那么可以用预处理3中的数组向下跳。
优化DP
例题
P5903 【模板】树上 K 级祖先
板子
题单
P5904 [POI2014] HOT-Hotels 加强版
长链剖分优化DP
未完待续!