1 条题解
-
0
题意理解
我们有一棵 个节点的树,表示 个城市和连接它们的道路。
有 次语言传播工作,第 次传播从 到 (走唯一的最短路径,即树上路径),把第 种通用语教给路径上的所有城市。
定义:两个城市 和 可以开展贸易,当且仅当存在一种通用语 ,使得 到 的路径上的所有城市都会语言 。
换句话说, 的路径必须完全包含在某一次语言传播的路径中。
我们需要统计有多少个无序对 ()可以开展贸易。
问题转化
对于任意两个城市 ,设 表示 到 的路径(按树上的唯一路径)。
条件:存在某次传播 ,其路径 满足 。
关键观察
-
路径包含关系
在树上,一条路径 被另一条路径 包含,当且仅当 的两个端点 都在 上,并且 是 的一段连续部分。
更准确地说:
设 的端点是 , 的端点是 。
则 当且仅当 $\mathrm{dist}(a, u) + \mathrm{dist}(u, v) + \mathrm{dist}(v, b) = \mathrm{dist}(a, b)$,
或者 $\mathrm{dist}(a, v) + \mathrm{dist}(v, u) + \mathrm{dist}(u, b) = \mathrm{dist}(a, b)$。
其实等价于: 都在 上,且 之间的路径是 的一部分。 -
等价条件
$$\mathrm{dist}(a, x) + \mathrm{dist}(x, y) + \mathrm{dist}(y, b) = \mathrm{dist}(a, b) $$
在树上,路径 被路径 包含的充要条件是:或者
$$\mathrm{dist}(a, y) + \mathrm{dist}(y, x) + \mathrm{dist}(x, b) = \mathrm{dist}(a, b) $$因为 ,这两个条件其实是对称的,就是 在 路径上且顺序是 (或 )。
-
简化判断
$$\mathrm{dist}(a, x) + \mathrm{dist}(x, b) = \mathrm{dist}(a, b) \quad\text{且}\quad \mathrm{dist}(a, y) + \mathrm{dist}(y, b) = \mathrm{dist}(a, b) $$
更简单的判断: 在路径 上,当且仅当:并且 之间的路径完全落在 上(自动满足,因为树上两点唯一路径)。
所以只需检查 和 是否都在路径 上。
暴力做法(小数据)
对于 ,我们可以:
- 预处理任意两点距离 (BFS 次,)。
- 对每对 (),检查是否存在一次传播 使得 和 都在路径 上。
判断 在路径 上的方法:
$$\mathrm{dist}(s_i, u) + \mathrm{dist}(u, t_i) = \mathrm{dist}(s_i, t_i) $$复杂度:,对于 可过。
优化思路
我们需要数有多少点对 满足:存在 使得 都在路径 上。
等价于:点对 如果被某条传播路径同时经过,则贡献 1。
转化为:对每个语言路径,数它包含的点对数量
对于一条语言路径 (长度为 个节点),它包含的点对数量是 。
但是不同语言路径可能包含相同的点对,直接相加会重复计数。
所以问题变成:给定 条树上路径,求它们的点并集的点对数量。
即:令 = 路径 上的点集,求 ,其中 表示 中所有点对。
容斥原理
设 表示事件“点对 被某条路径包含”。
我们要求:
$$\sum_{1 \le i < j \le n} [\exists k: (i,j) \in \mathrm{Path}(s_k, t_k)] $$这等于:
$$\sum_{1 \le i < j \le n} \left[ \bigvee_{k=1}^m (i,j \in P_k) \right] $$其中 是第 条路径的点集。
另一种思路:对每个点对,判断是否被至少一条路径包含
判断点对 是否被某条路径 包含:
路径 包含 当且仅当 包含 和 ,且 在 上连续(自动满足)。所以只需判断 是否同时在某条路径上。
高效算法()
我们可以用 树上差分 + LCA 来标记每条路径覆盖的边或点,但这里需要知道点对是否被同一条路径覆盖。
一个技巧:
对每个点 ,记录包含 的路径集合(用 bitset 或哈希),然后判断 是否有公共路径?
但 很大时不行。
正解思路(参考)
事实上,已知一个方法:
- 对每个语言路径,把它覆盖的边标记(用该语言的编号)。
- 点对 可行当且仅当 路径上的所有边都被至少同一种语言覆盖。
因为如果 路径上所有边都被某条语言路径覆盖,那么整条路径就被它包含。
问题转化为:给 条路径,标记边,问有多少点对之间的路径上的边都被至少一个共同语言覆盖。
进一步转化
对边考虑:每条边可能被若干种语言覆盖。
点对 可行当且仅当 路径上的所有边有一个公共的语言(不一定同一条路径,而是同一种语言编号)。因为一种语言对应一条路径,如果 路径上的边都被语言 覆盖,那么 路径一定完全在语言 的路径内部。
具体算法
- 对每种语言 ,它覆盖的边是 路径上的边。
- 对每条边 ,记录覆盖它的语言集合 。
- 我们要求点对 满足:。
也就是说, 路径上所有边的覆盖语言集合交集非空。
实现方法
- 对每种语言,路径 上的边加入语言 (用树上差分,给边打标记)。
- 然后问题变成:有多少点对,路径上的所有边都包含某种共同语言 。
换个角度:对每种语言 ,考虑所有被它覆盖的边,这些边形成一条路径(就是 路径)。
那么所有点对 如果完全在这条路径上,就满足条件。所以又回到:点对 满足它在某条语言路径上。
最终算法
我们只需对每条语言路径 ,计算它上面的点对数量 ,然后去重。
去重:如果两条语言路径有重叠的点对,只算一次。
这相当于求 条路径的点集的并集,然后计算这个并集中有多少点对。
去重方法
点对 可能出现在多条路径中,我们只计一次。
我们可以用 二维平面 扫描的方法,但较复杂。
一个简单方法:
对每个点对,它第一次被哪条路径覆盖?很难。但已知一个 做法(cf. 类似题目):
把路径按某种顺序处理,用并查集维护已经覆盖的连续段。
简单总结
对于本题 ,标算可能是:
- 求出每条路径的节点集合(用 O(1) LCA 可得路径长度)。
- 用容斥或线段树合并维护覆盖点对去重。
但实现较复杂,这里不展开代码。
公式总结
- 两点距离:$\mathrm{dist}(u, v) = \mathrm{depth}[u] + \mathrm{depth}[v] - 2 \times \mathrm{depth}[\mathrm{LCA}(u, v)]$
- 点 在路径 上:
- 路径包含点对:路径 包含点对 当且仅当 。
-
- 1
信息
- ID
- 4519
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 9
- 已通过
- 1
- 上传者