1 条题解
-
0
自动搬运
来自洛谷,原作者为

Alex_Wei
**搬运于
2025-08-24 22:48:44,当前版本为作者最后更新于2023-08-02 13:25:16,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
P9480 [NOI2023] 深搜
超级酷的题目!
思路参考了 Rainbow_qwq 的题解,对他的题解进行一些补充。题解最后给出的代码有: 的性质 B,,未卡常正解和卡常后的正解。
首先, 可以作为 -DFS 树的充要条件是所有非树边均为返祖边,因为 DFS 树的非树边为返祖边,且如果满足条件则对 进行 DFS 就是符合条件的 DFS 顺序。
称非树边 覆盖 点 当且仅当 在以 为根的 上是横叉边(非返祖边)。易知非树边 不覆盖 点 当且仅当 在以 为根时 的子树内(称为 侧),或以 为根时 的子树内(称为 侧)。
对于性质 B,有两种思路:
- 记录从子树内向上延伸的返祖边的最浅深度,并维护当前子树内是否有关键点未被覆盖。
- 设 表示不覆盖 中任意关键点的非树边数量,设关键点集合为 ,容斥得 $\sum_{|S| \geq 1 \ \land \ S\subseteq U} (-1) ^ {|S| + 1} 2 ^ {c(S)}$。
顺着前一种思路不容易解决原问题,因此考虑第二种思路。
非树边的形态
- 称一个点 属于虚树,当且仅当它是虚树的结点。
- 称一个点 落在虚树上,当且仅当它被虚树的某条边覆盖。
定点 为根。
建出 的虚树 。注意要和我们所理解的虚树做区分:当且仅当 或有至少三棵子树(包括向上的子树)含属于 的点时, 才属于虚树。它们的唯一区别在于,当 所有点的 LCA 只有两棵子树含属于 的点时, 不属于 ,但 属于我们通常所理解的虚树。
考虑非树边 不覆盖 的充要条件: 全部在 侧, 全部在 侧, 侧均有属于 的点。它将合法非树边的形态分成两类:
- 落在虚树上的点向虚树外延伸的某条边的对应子树内的返祖边。注意 “返祖边” 是在以该点为根时判定的。
- 对应树上路径被虚树的某条边完全包含。

如上图,绿色的点表示 ,黄色的点不属于 但属于虚树,橙色的点不属于虚树但落在虚树上。红色虚边为合法非树边,蓝色虚边为不合法非树边。
性质 B
对于性质 B,注意到不存在跨过 的合法横叉边,因此可以将虚树改为我们通常所理解的虚树:若 有两棵子树含属于 的点,则 也属于虚树。即认为 属于虚树对答案无影响。
枚举 的 LCA ,则不存在一端在 子树内(不含 ),另一端在 子树外的(不含 )的合法非树边。因此子树内外独立,贡献直接相乘。
- 子树内的贡献可利用虚树结构 DP,因此设 表示当 属于虚树 时,仅考虑 子树内所有关键点和非树边的贡献。
- 子树外的贡献为 ,其中 表示 子树外以 为根时的返祖边数量。设 表示 子树内以 为根时的返祖边数量,换根 DP 求出 和 。 的求法稍有些复杂,留给读者自行思考,可以参考代码
dfs3部分。
的转移是重头戏。转移时,需要不重不漏地统计每一处贡献。为此,请读者牢记所有可能产生贡献的非树边形态:落在虚树上的点向虚树外延伸的某条边的对应子树内的返祖边;返祖边两端对应树上路径被虚树的某条边完全包含。
设 的所有儿子为 。 的子树内要么没有虚树上的点,要么有虚树上的点。对于后者,根据虚树的性质,有且仅有最浅的点与 在虚树上相连。
设 在虚树上的儿子为 ,有基本贡献系数 。接下来统计未考虑到的非树边:
- 第一类非树边:对于每个 ,包含于路径 的非树边。
- 第二类非树边:对于每个 和所有 (不含 ),从 向虚树外延伸的某条边的对应子树内的返祖边。
- 第三类非树边:对于 ,向虚树外延伸且在子树内的某条边的对应子树内的返祖边。
将第三类非树边摊到每个未选点的儿子,得:
- 对于选点的儿子 ,贡献系数为 $X(s_i) = \sum_{p\in \mathrm{subtree}(s_i)} g_{p\to d}$,其中 表示 乘以 ,其中 表示包含于路径 的非树边数量,加上对于所有 (不含 ),从 向路径 外延伸的某条边的对应子树的返祖边数量之和。
- 对于未选点的儿子 ,贡献系数为 ,其中 表示 子树内的返祖边数量 ,加上较浅的一端为 ,较深的一端落在 子树内的返祖边数量。

如上图, 的左子树选择点 ,红色虚边为产生贡献的非树边。 的右子树没有选择,红色虚边为产生贡献的非树边。
假设已经求出 和 ,考虑 如何计算。设恰好在 棵子树内选点的答案为 ,即 。
- 如果 ,则至少要有两棵子树被选择,产生贡献 。
- 如果 ,则要求 是关键点,对被选择子树数量没有限制,产生贡献 。
发现 的 等价,因此背包时维护 和 即可。
设 ,则 $Z = \sum_{|S|\geq 1 \ \land \ S\subseteq U} (-1) ^ {|S|} 2 ^ {c(S)}$,答案为 。
考虑维护 求 。根据 的定义,可得如下步骤:
- 首先,对于 ,令 ,其中 是 对应的 的儿子。
- 对于所有 ,令 。由于不存在等于树边的非树边,将这一步放在下面两步之后也正确。
- 加入第一类非树边的贡献:枚举所有以 为一端,另一端在 子树内的非树边 ,对于 ,将 乘以 。
- 加入第二类非树边的贡献:枚举所有以 为一端,另一端在 子树内的非树边 ,设 对应 的儿子为 ,则对于 的所有不为 的儿子 ,对于 ,将 乘以 。简单地说,返祖边 (其中 是较浅端)会对 的不为 后继的所有儿子的子树内所有结点产生贡献。
我使用的维护方法是:继承 ;加入第一类非树边的贡献;计算 求出 ;加入以 为较浅端的第二类非树边的贡献;令 。其实就是将统计第二类非树边的贡献下放到每个儿子处进行,这样好写一点,但注意这类贡献需要在计算 求出 之后统计。
将 这一维用 DFS 序拍平到序列上,线段树合并维护 ,支持区间乘法,区间求和。注意到每个子树的时间戳区间不交,所以不用线段树合并,只需用一棵线段树维护。
考虑求 。在计算 ,加入第一类非树边的贡献时,对于每个 以及对应 的儿子 ,将 加上 ,过程结束后得到新的 。则 。
时间复杂度 。
正解
相较于性质 B 多出了以 为根时的横叉边。
考虑在何种情况下性质 B 的做法会导致错误:性质 B 保证我们可以将 加入虚树,而性质 B 的做法在 “无论非树边是否是返祖边,只要 在虚树上” 时,均可得到正确的答案,因为我们在分析合法非树边形态时,并没有要求这些非树边是以 为根时的返祖边。这说明性质 B 只是 让我们将 加入虚树。
将 加入虚树会导致一些非树边从合法变成不合法。
- 对于形如 “落在虚树上的点向虚树外延伸的某条边的对应子树内的返祖边” 的非树边,由于将 加入虚树不改变落在虚树的点集,因此不会有影响。
- 对于形如 “ 对应树上路径被虚树的某条边完全包含” 的非树边,将 加入虚树后产生的影响为:若虚树原本不包含 ,且存在经过 的虚树边 ,那么一条两端均属于 树上路径,且两端分别在 的两侧的非树边从合法变成了不合法。
因此,只需重新计算这样的 的贡献:,且 恰有 两棵子树有属于 的点。
枚举 和将 加入虚树后它在虚树上的两个儿子 ,设它们分别对应 在原树上的儿子 。设 $z = g_{p\to d} \times g_{q\to d}\times \prod_{s_i \neq u, v} Y(s_i)$,这是原来计算的贡献。枚举 LCA 为 的非树边 ,若 分别在 和 上(路径不含 , 顺序无关),则将 乘以 。最终得到 为真正的贡献。暴力做的复杂度是 。
先将 子树时间戳区间的所有 值乘以 ,最后将贡献乘以 (我们发现,实际上 ),这样贡献只与 和 有关,而与其它儿子无关。
枚举 ,则一条 LCA 为 的非树边的贡献是矩形乘以 。若干次矩形乘以 之后全平面求和,注意容斥掉 的贡献。我使用的维护方法是:支持查找子树内某点 对应的 的儿子在时间戳上的后继 。扫描线,将所有儿子的时间戳加入事件,则遇到事件 时(当前扫到时间戳 ,操作为给 乘以 ),设上一次考虑的时间戳为 (初始值为 的儿子时间戳最小值 )。因为所有儿子的时间戳也被加入了事件,所以 一定是同一个儿子子树内的时间戳。求出 的 值之和,求出 的 值之和( 表示 的子树时间戳最大值 ),相乘后再乘以 加入答案。
最后不要忘记将答案减去 ,也就是减去原先计算的错误答案。为此,需要区分 和 ,背包时维护 。
时间复杂度 ,空间复杂度为 ,加上求 LCA 的空间复杂度。代码。
- 1
信息
- ID
- 8956
- 时间
- 4000ms
- 内存
- 512MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者