20240806:点分治,虚树选做

P4178 Tree

题意:给定一棵树,求多少无序对 \((u, v)\) 满足 \(\text{dist}(u, v) \le k\)

对于树上的路径进行分类:经过根;不经过根。

第二类路径点可以通过递归子树求出。

对于经过根的路径,可以一遍 dfs 求出每个点到根的距离 \(\text{dis}(u)\)

问题转化为求 \(\text{dis}(u) + \text{dis}(v) \le k\)\(u, v\) 不在同一棵子树的点对数。

如果没有后面子树的限制,可以简单的排序 + 双指针求出,那么只要把每棵子树多算的减掉即可。

单次复杂度 \(O(n\log n)\)。如果直接递归,复杂度高达 \(O(n^2\log n)\)

考虑 \(rt\) 选取当前树的重心(最大子树最小)。

\(rt\) 的每棵子树大小不大于 \(n/2\),如果存在子树 \(u\) 大于 \(n/2\),以 \(u\) 为重心不会比 \(rt\) 更劣。

因此每次都选重心,树的大小至少减少一半,最多递归 \(O(\log n)\) 层,每层总结点数 \(O(n)\)

时间复杂度 \(O(n\log^2 n)\)submission

P9058 [Ynoi2004] rpmtdq

题意:对于一棵树有 \(q\) 次询问:给定 \(l, r\),求 \(\min\limits_{l\le i < j \le r} \text{dist}(i, j)\)

总共 \(O(n^2)\) 个点对,考虑哪些一定不可能成为答案。

如果 \((x_1, y_1),\ (x_2, y_2)\) 满足 \(x_1 \le x_2 < y_2 \le y_1\)\(\text{dist}(x_2, y_2) \le \text{dist}(x_1, y_1)\)

那么对于任何询问,选 \((x_2, y_2)\) 一定不劣于选 \((x_1, y_1)\),我们称 \((x_2, y_2)\)有效的。

点分治处理路径问题,只统计经过 \(rt\) 的有效点对 \((i, j)\)(不妨钦定 \(\text{dist}(i, rt) \le \text{dist}(j, rt)\))。

设当前在处理点 \(u\),哪些不在同一子树中的点 \(v\) 会与 \(u\) 组成有效点对。

定义 \(pre_u\) 表示满足 \(\text{dist}(v, rt) \le \text{dist}(u, rt)\) 的小于 \(u\) 的最大 \(v\)

现在证明为什么 \((v, u),\ v < pre_u\) 是没用的。

对于 \(v < pre_u\),有

\[\text{dist}(v, pre_u) \le \text{dist}(v, rt) + \text{dist}(pre_u, rt) \le \text{dist}(v, rt) + \text{dist}(u, rt) = \text{dist}(v, u) \]

显然 \((v, u)\) 对于 \((v, pre_u)\) 而言是无效的,与假设矛盾。

定义 \(nxt_u\) 表示满足 \(\text{dist}(v, rt) \le \text{dist}(u, rt)\) 的大于 \(u\) 的最小 \(v\)。同理证明 \((u, v),\ v > nxt_u\) 是没用的。

总结:任意点 \(u\) 只有 \((pre_u, u)\)\((u, nxt_u)\) 是有效的。

但是 \((v, u)\) 还要求在不同子树,假设 \(pre_u\) 恰与 \(u\) 在同一子树,只会使得 \(\text{dist}(pre_u, u)\) 变得更小,因此不需要考虑子树限制。

\(u\) 一次只产生 \(O(1)\) 个点对,因此整个分治过程产生 \(O(n\log n)\) 个点对。

将询问离线,转化为二维数点,时间复杂度 \(O(n\log^2 n)\)

点对 \((i, j)\) 的权值 \(\text{dist}(i, j)\) 可以直接用 \(\text{dist}(i, rt) + \text{dist}(j, rt)\),这样带来的问题是 \(i, j\) 在同一子树的距离是错误的。

我们总能递归到 \((i, j)\) 经过的一个重心,在这个中心上一定能正确的求出 \((i, j)\) 距离或者产生更优点对。

还有一个问题是如何求前驱后继,对于 P9678 来说,用 set 维护足矣,但本题还需进一步卡常。

\(d(u) = \text{dist}(u, rt)\),将二元组 \((u, d(u))\) 根据 \(u\) 排序。维护一个 \(d\) 值单调不降的单调栈,可以求出所有前驱。后继同理。

submission

P4292 [WC2010] 重建计划

题意:给定一棵树,求长度属于 \([L, U]\) 的路径的最大价值,路径 \(S\) 的价值定义为 \(\dfrac{\sum_{e \in S} w(e)}{\vert S\vert}\)

对于一条路径,如果 \(\sum_{e \in S} \bigg(w(e) - \text{avg}\bigg) \ge 0\),说明这条路径的价值一定大于等于 avg。

不难想到二分答案,把每条边都减去 mid 后检查长度属于 \([L, U]\) 的最大路径和是否非负。

还是通过经过哪个重心来划分路径,设当前重心为 \(rt\)

\(f_i\) 表示在已经遍历完的子树里深度为 \(i\) 的点到根的最长距离, \(g_i\) 表示在当前子树里深度为 \(i\) 的点到根的最长距离。

显然用 \(\max\limits_{j \in [i - U + L,\ i]} f_{j} + g_{U - i}\) 去更新答案。

前面一项很容易用数据结构维护,但是加上点分治和二分复杂度有三个 log,无法通过。

发现 \(f\) 的答案区间是一个单调队列的形式,时间复杂度 \(O(\text{当前子树深度 + 之前出现过的最大子树深度})\)

这样复杂度还是可能退化到 \(O(n^2)\),但是如果按深度从小到大枚举子树,统计答案这一步就是线性的。

如果直接点分治的同时去排序,仍然是三个 log 的。但是点分树的形态始终不变,我们可以在二分之前对于每个重心先排好序。

这样整体就是双 log 复杂度。submission

CF150E Freezing with Style

题意:给定一颗带边权的树,求一条边数在 \([L, R]\) 之间的路径,并使得路径上边权的中位数最大。输出一条可行路径的两个端点。

对于序列 \(a\),定义 \(b_i = \begin{cases}1& a_i \le \text{mid}\\ -1 & \text{otherwise}\end{cases}\),如果满足 \(\sum b_i > 0\),则 \(a\) 的中位数一定不大于 mid。

和上题做法一致,二分答案,如果存在路径满足 \(\sum b_i < 0\),说明答案还能变大。

\(\text{val}\) 为使所有合法路径 \(\sum b_i \ge 0\) 的最小值,那么所求答案即 \(\text{mid = val - 1}\) 时使 \(\sum b_i\) 最小的路径两端。

subsmissin

CF1260F Colored Tree

题意:

给定一棵树,每个节点有一个颜色 \(h\)\(h_i\)\([l_i,r_i]\) 内的一个整数。

对于全部 \(M = \prod (r_i-l_i+1)\) 种不同的染色方案,求:

\[\sum_{h_i=h_j,1\leq i<j\leq n} \text{dist}(i,j) \pmod {10^9 + 7} \]

\(\text{dist}(i, j)\) 对答案的贡献有 $\big(d(i, rt) + d(j, rt)\big)\times \vert H_i\cap H_j\vert \times \prod_{k \ne i, j} (r_i - l_i + 1) $。

不妨只考虑交集中的某一点 \(x\) 对答案的贡献:

\[\begin{aligned} w(i, j) + w(i, k) =& (d_i + d_j) \times \dfrac{M}{L_j \times L_i} + (d_i + d_k) \times \dfrac{M}{L_k \times L_i}\\ \\ \implies& \dfrac{d_i}{L_i} \times(\dfrac{1}{L_j} + \dfrac{1}{L_k}) + \dfrac{1}{L_i} \times(\dfrac{d_j}{L_j} + \dfrac{d_k}{L_k}) & M \text{ 每项都有,可以最后再乘}\\ \end{aligned} \]

线段树维护交集贡献,时间复杂度 \(O(n \log^2 n)\)

懒标记线段树爆了,考虑树状数组维护区间加区间和。

维护差分数组 \(b_i\)\(\sum a_i = \sum b_i \times (n - i + 1) = (n + 1) \times \sum b_i - \sum b_i \times i\)

后面一个和式也用树状数组维护即可。submission

[HZOI 2015] 树黑白

题意:给定一棵树,一开始都是白色,支持两种操作:

  • \(u\) 反色。
  • 查询 \(u\) 到所有黑色节点的距离和。

\(u\) 的路径按照经过哪个重心分成 \(O(\log n)\) 类。

因此不管修改还是查询都只要在点分树上暴力跳 \(\log n\) 次。

\(fa(x)\) 表示 \(x\) 在点分树上的父亲节点,定义 \(x\) 的子树为以 \(x\) 为分治中心时的子树。

\(f_x\) 表示 \(x\) 子树内的黑点到 \(x\) 的距离和,\(g_x\) 表示 \(x\) 子树内的黑点到 \(fa(x)\) 的距离和,\(cnt_x\) 表示 \(x\) 子树内的黑点数。

\(x\) 一直跳到点分树的根,假设当前点是 \(cur\),上一个点是 \(pre\)\(fa(pre) = cur\)):

那么 \(cur\) 对询问 \(u\) 的贡献有

\[ f_{cur} - g_{pre} + (cnt_{cur} - cnt_{pre}) \times \text{dist}(u, cur) \]

submission

P2056 [ZJOI2007] 捉迷藏

题意:给定一棵树,初始全黑。支持单点改色,询问最远两个黑点距离。

类似直径求法,每个分治重心维护子树内黑点到 \(rt\) 的最大值与次大值,可删堆维护。

mutiset 常数过大了,手写一个懒删除堆。submission

P3345 [ZJOI2015] 幻想乡战略游戏

题意:给定一棵树,保证每个点度数不超过 \(20\)。单点修改点权 \(a_i\),每次查询最小的 \(f(u) = \sum_{v = 1}^n \text{dist}(u, v) \times a_v\)

考虑暴力做法:

设当前在点 \(u\)\(\sum_u\) 表示 \(u\) 子树内的点权和,\(\sum = \sum_{i = 1}^n a_i\)

与之直接相连的儿子 \(v\)\(u\) 更优当且仅当 \(\text{dist}(u, v)\times (\sum - 2\sum_v) < 0\)(考虑答案的变化量)。

也就是 \(2 \sum_v > \sum\),如果存在儿子节点更优,那么只可能有一个 \(v\) 满足条件(\(2\sum_v > \sum \ge \sum_u\))。

  • \(f(v) \ge f(u)\)

\(v'\)\(v\) 子树中的一点。

由于 \(\sum\) 是常量,且 \(\sum_{v'} \le \sum_{v}\),因此从 \(u\) 走到 \(v'\) 只会使答案越来越大。

因此 \(v\) 的子树中不存在比 \(u\) 更优的点。

  • \(f(v) < f(u)\)

    \(v'\) 为最优决策点。

    显然 \(v'\)\(v\) 的子树内,现在证明不管从 \(v\) 子树的哪个点 \(x\) 出发(将 \(f(x)\)\(x\) 的儿子比较)都能到达 \(v'\)

    砍掉多余部分,只留 \(v'\) 的子树。

    强制使 \(x\) 为根,由于 \(2\sum_{v'} > \sum\),一定有 \(2\sum_{fa(v')} > \sum\),因此存在一条 \(v'\)\(x\) 的决策路径。

修改和单点查 \(f\) 可以用点分治轻而易举做到 \(O(\log n)\),瓶颈在与上述算法最坏会达到单次 \(O(n\log n)\)

一个想法是枚举 \(x\) 的儿子 \(y\)(原树),如果 \(f(y) < f(x)\),说明最优决策点在 \(y\) 的分治子树中,递归到包含 \(y\) 的儿子(点分树)。

时间复杂度 \(O(20\log^2n)\),正确性可以由上述第二点得到。

加强版少去了度数限制,做法是链剖 + 线段树,待补。

submission

P2495 [SDOI2011] 消耗战

题意:给定一棵树,\(m\) 次询问:给出 \(k\) 个关键点,求使每个点都不能到的最根小代价(花费 \(w(u, v)\) 使 \((u, v)\) 断掉)。

设关键点集为 \(S\)

显然有 \(O(n)\) 的树形 dp,\(f_x\) 表示使 \(x\) 内关键点都不能到根的最小代价:

\[f_x = \begin{cases} w\big(x, fa(x)\big) & x \in S \\ \\ \min\bigg( w\big(x, fa(x)\big),\ \sum_{y \in son(x)} f_y\bigg) & \text{otherwise} \end{cases} \]

仅保留关键点之间的祖先后代关系(保留根节点,和关键点两两之间的 lca)不会改变最后的 dp 值。

\[f_x = \begin{cases} x\text{ 与在虚树中的父亲之间的最小边权,倍增解决} & x \in S \\ \\ \min\big(w,\ \sum_{y \in son'(x)} f_y\big) &\text{otherwise}\end{cases} \]

定义虚树为包含关键点和所有 lca 的最小树。

以下构造方式能说明虚树规模只有 \(O(k)\),如果能快速建出虚树即可解决本题。

二次排序 + LCA 连边

  • 将关键点按 DFS 序排序;
  • 遍历一遍,任意两个相邻的关键点求一下 LCA,并且判重;
  • 然后根据原树中的祖先后代关系建树。

具体实现上,在关键点序列上枚举相邻的两个数,两两求得 LCA 并且加入序列 \(A\) 中。

此时 \(A\) 一定包含了虚树中的所有点(可能重复)。

假设 \(a, b, c\) 按照 dfs 序依次递增,则

\[\text{lca}(a, c) = \text{lca}\big(\text{lca}(a, b),\ \text{lca}(b, c)\big) \]

由于 \(\text{lca}(a, b)\)\(\text{lca}(b, c)\) 都是 \(b\) 的祖先,因此其中一个一定是另一个的祖先。

假设按照时间戳排序得到 \(x_1, x_2 \cdots x_m\)

那么任意的两个节点的 lca 可以写做

\[\text{lca}(a_i, a_j) = \text{lca}\bigg(\text{lca}(a_i, a_{i + 1}),\ \text{lca}(a_{i + 1}, a_{i + 2}),\ \cdots,\ \text{lca}(a_{j - 1}, a_j) \bigg) \]

任意两个关键点的 lca 都包含在我们新增的相邻 lca 里。

同时证明了虚树规模是 \(O(k)\) 的。

\(A\) 按照 dfs 序排序并去重。枚举相邻的两个点 \(x,y\),连接 \(\text{lca}(x, y)\)\(y\),这样就完成了构造。

为什么这样连边不重不漏?

如果 \(x\)\(y\) 的祖先。

由于 \(x, y\)\(A\) 中相邻,因此 \(x\)\(y\) 的链上不存在任何其他节点,直接 \(x\) 连向 \(y\) 即可。

如果 \(x\) 不是 \(y\) 的祖先。

\(\text{lca}\) 的 dfs 序一定小于 \(x\),因此 \(x\)\(\text{lca}\) 在之前已经直接或间接相连了。

又由于 \(x, y\) 相邻,\(\text{lca}\)\(y\) 之间不存在其他点,\(\text{lca}\) 连向 \(y\) 是不重不漏的。

submission

P3320 [SDOI2015] 寻宝游戏

题意:每次新增或减少一个关键点,并询问包含所有关键点的生成子树的边权和 \(\times 2\)

这颗生成子树的根一定是所有关键点的最近公共祖先,因为任意两点要求联通。

发现这与我们构建虚树的形式很像,可以单次 \(O(k\log n)\) 得到整棵树的边权和。

但是本题并不保证 \(\sum k\) 的量级。

Gym - 104128E

题意:给定一颗树,初始全白,问全部染黑的最小代价。把 \(x\) 子树里与 \(x\) 距离为 \(i\) 的点全部染黑代价为 \(a_i\)

\(f(x, d)\) 表示在以 \(x\) 为根的子树里把深度为 \(d\) 的点全部染黑的最小代价,答案为 \(\sum f(root, *)\)

\[f(x, d) = \min\bigg(a_{d - dep(x)},\ \sum_{y \in son(x)}f(y, d) \bigg) \]

对于每个深度建出虚树,时间复杂度 \(O(n\log n)\)

submission

posted @ 2024-08-06 13:12  Lu_xZ  阅读(15)  评论(0编辑  收藏  举报