树分治

算法相关

对树分治的浅尝辄止,以后可能会把比较难的题目放上去。

点分治

适合处理大规模的树上路径问题,要求离线、静态。

不妨考虑一个子树 \(x\) 的问题。我们可以把这棵子树内的路径划分为两种:经过 \(x\) 的和不经过 \(x\) 的。这样两者并起来显然是全集。记 \(x\) 的子树大小为 \(sz_x\),若处理问题 \(f(x)\) 的复杂度是 \(O(sz_x \operatorname{poly} \log sz_x)\),则该问题可以由点分治高效处理。考虑每次分治将重心拎出来当根,则每次子树大小至少减半,分治层数为 \(O(\log n)\) 级别的。具体的时间复杂度为:\(T(n) = T(\frac{n}{2}) + O(n \operatorname{poly} \log n) = O(n \operatorname{poly} \log n)\)。

点分树

与点分治能处理的问题类似,不同的是它可以在线和带修。

具体而言,点分树是一棵按如下操作生成的重构树:

  • 找到当前处理的树的重心,并钦定其为根。
  • 将该层根的父亲设置为上一层的根。
  • 向根的所有儿子递归问题。

点分树有如下性质:

  • 树高级别为 \(O(\log n)\)。
  • 点分树上 \(\operatorname{LCA}(x, y)\) 在 \(x \rightsquigarrow y\) 路径上。
  • $sub(x) \setminus x $ 的信息与 \(x\) 无关。

性质 \(1, 3\) 均由点分治的性质保证。性质 \(2\) 的感性证明是,在原树上以 \(\operatorname{LCA}(x, y)\) 为根时,\(x, y \in \operatorname{sub}(\operatorname{LCA}(x, y))\)(这是显然的),此时一定存在 \(x \rightsquigarrow \operatorname{LCA}(x, y) \rightsquigarrow y\) 这条路径。由于树上简单路径唯一,则 \(\operatorname{LCA}(x, y)\) 自然在 \(x \rightsquigarrow y\) 这条路径上。

习题

P3806 【模板】点分治

思路

模板。用 \(f_i\) 表示路径长度为 \(i\) 的答案。

P4178 Tree

思路

用 BIT 维护当前不超过长度 \(k\) 的路径数量,查询的话是一次拼接,只需减去即可。

P4149 [IOI 2011] Race

思路

思路和上一题相似,只不过 BIT 内维护的信息变为路径的权值。

P4149 [IOI 2011] Race

思路

与模板题很像,\(f_i\) 表示路径长度为 \(i\) 的最小边权。

P6626 [省选联考 2020 B 卷] 消息传递

思路

由于一个点的查询可能与其父亲相关,因此我们需要处理当前根 \(x\) 的所有儿子子树内的所有点的询问。查询一个儿子的子树时,先清空该子树的信息再去算贡献,算完之后加回来即可。复杂度不变,只是多了个常数。

P10421 [蓝桥杯 2023 国 A] 树上的路径

思路

同样地,先记 \(f_i\) 表示路径长度为 \(i\) 的答案。

泛化 \(dis(i, j) = k\)。

原式变为:

\[\sum_k k \times f_{i - k} \]

通过一些变换可以得到:

\[\sum_k i \times f_{i - k} - \sum_k (i - k) \times f_{i - k} \]

只需要 BIT 维护 \(f_i\) 和 \(i \times f_i\) 即可。

P6329 【模板】点分树 / 震波

思路

对于每个点维护 BIT 表示该点子树内所有点到它的距离。由于上述点分治 \(2, 3\),我们可以通过暴力跳父亲的方法进行修改和查询。但是这样会重复统计贡献,也就是形如同一条链统计两次的情况。这时候我们再对于每个点维护一个 BIT 表示该点父亲与该点答案重合的贡献。那么这样对于每个修改,可以直接更改这两个 BIT;对于每个查询,可以先查询该点父亲的答案,再减去该点与其父亲的重合贡献。

P10603 BZOJ4372 烁烁的游戏

思路

修改查询对调了,其余无异,那么也是好做的。

posted @ 2026-10-07 23:09  endswitch  阅读(4)  评论(0)    收藏  举报