树分治初探

点分治

静态点分治

每次选择树的重心,删掉后考察其他位置,分治处理 .

因为选的是重心所以每次深度至少除以二,那么只有 \(\log n\) 层 .

例 1

给一棵 \(n\) 个点的树,对于所有 \(k\) 求长为 \(k\) 的路径数量 .

点分治,每次选重心,过重心的路径可以刻画为每个子树的深度数组选两个卷起来,这个可以卷积 .

动态点分治 / 点分树

对于点分治的重心结构按层建树,即如果 \(p\)\(q\) 的下一层分治重心,则 \(p\)\(q\) 的儿子 .

一种应用是对每个点统计点分治的信息,另一种应用是利用只有 log 层加速跳跃 .

例 2

给定一棵 \(n\) 个点的带权树和正整数 \(k\),求每个点到其它所有点的距离中第 \(k\) 大的数值 .

首先起手二分答案变成找 \(\le w\) 的路径数,每次处理到 \(x\)\(\operatorname{fa}(x)\) 的距离排序后的数组统计后容斥即可 .

例 3

给一棵树和正整数 \(a\),对每个点 \(u\)\(\sum_{i=1}^na^{\operatorname{dist}(i,u)}\) .

点分树上考虑一个分治重心 \(u\) 的每种子树对其它子树的贡献,线段树维护即可 .

例 4

给一棵树,点有点权边有边权,每次修改点权,查 \(\sum_v\operatorname{dist}(u,v)\cdot w_u\) 的最小值 .

\(\deg(u)\le 20\) .

考虑一次操作有什么影响,假设当前答案是 \(u\) . 以 \(u\) 为根考虑,\(\operatorname{sumd}(u)\)\(u\) 子树内的 \(\sum d\)\(v\)\(u\) 的一个儿子 . 简单讨论可以得到改成 \(v\) 更优当且仅当 \(2\cdot\operatorname{sumd}(v)>\operatorname{sumd}(u)\) .

考虑怎么快速跳,在点分树上考虑,每次只需要跳 log 步,然后就行了 .

想要不依赖度数需要先三度化 .

边分治

三度化

对于一棵带权树,想要在不改变任意两点间距离的情况下,转化成带权二叉树 .

考虑对于每条边 \((u,v,w)\),建立虚拟点 \(x\),连 \((u,x,0),\,(x,v,w)\),然后把 \(u\) 的别的边连到 \(u\) 上 .

虽然有二倍常数但是写起来舒服 .

静态边分治

类似静态点分治,每次取一条边将树尽量均匀的划分,并递归处理 .

然而会被菊花轻松卡掉,不过先三度化就对了 .

复杂度分析:分治树只有 \(\log\) 层,三度化只增加 \(O(n)\) 个点 .

由于每次只需要合两个位置所以在处理方面比点分治方便一些 .

例 5

给一棵 \(n\) 个结点的树,每条边上有一个一次函数 \(ax+b\),对于每个 \(x\) 求路径上函数值之和最大的路径 .

应当是维护答案的凸包,边分治后只需要合并两个凸包,合并路径就是按位相加,合并子树和整体的贡献就是 Minkowski 和 .

有一些涉及多个树统计的问题也可以起手一个边分治做 .

例 6

给两棵带权树,求:

\[\max_{u,v}\{\operatorname{dep}_1(u)+\operatorname{dep}_1(v)-(\operatorname{dep}_1(\operatorname{lca}_1(u,v))+\operatorname{dep}_2(\operatorname{lca}_2(u,v)))\} \]

对第一棵树边分治,令靠近根的一侧点集是 \(S_1\),另一侧是 \(S_2\),那么对于 \(S_1\) 中的每个点 \(u\),对 \(S_2\) 中的任意点 \(v\)\(\operatorname{lca}_1(u,v)\) 都是一定的,从而可以确定 \(\operatorname{dep}_1(u)-\operatorname{dep}_1(\operatorname{lca}_1(u,v))\) .

接下来对于第二棵树要求关于 LCA 的统计信息,这是经典问题,虚树上换根 DP 即可 .

类似的题目:WC2018 通道 .

链分治

树链剖分与动态链分治

树链剖分分为重链剖分和长链剖分两种 .

重链剖分:又称轻重链剖分,对于每个点定义重儿子为子树大小最大的儿子,这样每条链被划分为 \(O(\log n)\) 条重链(即由重边组成的链),可以分别用数据结构维护 .

长链剖分:对于每个点定义重儿子为子树深度最大的子结点,这样每条链被划分为 \(O(\sqrt n)\) 条重链,在深度相关的问题上较为有效 .

例 7

维护一棵带权树,支持链加链求和 .

树链剖分,对每条链开一个线段树(或者直接在 DFS 序上建)维护即可 .

例 8

给一棵树,求有多少互不相同的 \(a,b,c\) 满足 \(\operatorname{dist}(a,b)=\operatorname{dist}(b,c)=\operatorname{dist}(a,c)\) .

对于一组 \((a,b,c)\) 考察其中心点的位置 \(u\) 使得 \(\operatorname{dist}(u,a)=\operatorname{dist}(u,b)=\operatorname{dist}(u,c)\),对 \(u\) DP 依次合并每条链即可转移,大概是一个卷积的形式 .

由于是与深度有关的 DP,考虑长链剖分,对于每个点继承重儿子并依次加入轻儿子,因为从某个点向其祖先跳,长链一定不变短,从而可以均摊到线性 .

静态链分治

又称 dsu on tree,在子树统计问题中可以考虑先继承重儿子然后依次加入轻儿子然后再合并轻儿子贡献 .

长链剖分的情形我们已在例 8 中理解,下面放一些重链剖分的例题 .

例 9

给一棵树,求每个子树内的颜色个数 .

重链剖分,每次继承重儿子贡献,然后依次合并轻儿子贡献,走一次轻边子树大小至少除以二,所以是一个 log .

例 10

给一棵 \(n\) 个点的树,每个点有点权,算所有独立集点权乘积之和 . 模数 NTT 友好 .

考虑经典的独立集 DP,这里合并是卷积,对于链可以分治乘出来 . 对于任意树只需要链分治然后把轻儿子合并到重链上即可 .

可能这个动态 DP 有点不太亲民,算了 .

posted @ 2023-12-14 21:29  Jijidawang  阅读(117)  评论(0编辑  收藏  举报
😅​