Codeforces 1486F Pairs of Paths
Description
给定一棵大小为 $n$ 的树和 $m$ 条链 $(u, v)$。统计有多少对链,满足这两条链恰好有一个交点。
$n, m \le 3 \times 10^5$
Solution
不妨钦定 $1$ 为根分析。
考虑如下问题:恰有一个交点的两条链会长成什么样子。
其实分为两种情况:一是它们的 $\text{LCA}$ 相同,而是它们的 $\text{LCA}$ 不同。如下图所示。
左图中 LCA 表示两条链 $A, B$ 公共的 $\text{LCA}$,而右图中 LCA 则是 $A$ 的 $\text{LCA}$(也就是两条链的 $\text{LCA}$ 中较深的那一个)。
现在,我们对于给定的一条链 $(u, v)$,求出它的三个值:$lca, a, b$。$a$ 表示 $u$ 在 $lca$ 的哪一棵子树中,$b$ 表示 $v$ 在 $lca$ 的哪一棵子树中。或者可以理解为,设 $u$ 与 $lca$ 的深度差为 $k$,则 $a$ 是 $u$ 的 $k-1$ 级祖先,$b$ 是 $v$ 的 $k-1$ 级祖先。值得注意的是,可能 $u, v$ 互为祖先—后代关系,比如 $u$ 是 $v$ 的祖先,那么我们可以钦定 $a$ 为一个新开的点,避免对后面的统计造成影响。同时为了方便,请确保 $a<b$,这一点可以通过交换 $u, v$ 和 $a, b$ 很简单的达到。
现在,我们分别考虑求出上面两种情况对答案的贡献。
先考虑第一种情况,我们可以把所有的链先按 $lca$ 的深度,再按 $lca$ 排序。对于 $lca$ 相同的一些链,显然我们求的就是 $\boldsymbol{a_x, b_x, a_y, b_y(a_x<a_y)}$ 互不相同的链对 $\boldsymbol{(x, y)}$ 的数量。为了确保不重不漏,我们不妨按照 $a$ 严格递增的顺序去一段一段地枚举链 $y$,同时开个桶 $buk_i$ 记录一下从子树 $i$ 中伸出来的链的条数。每次 $ans \gets ans + cnt - buk_{b_y}$,然后分别把 $buk_{a_y}, buk_{b_y} + 1$ 就好了。上面 $cnt$ 表示的是已经枚举过的链的条数。具体细节参考代码。
考虑第二种情况,我们依然可以把所有的链先按 $lca$ 的深度,再按 $lca$ 排序。设以 $u$ 为根的子树对应 $\text{DFS}$ 序上 $[\textit{ldf}_u, \textit{rdf}_u]$ 这一段。用树状数组维护一个 $\text{DFS}$ 序,每次 $ans \gets ans + \operatorname{Sum}(\textit{ldf}_{lca}, \textit{rdf}_{lca})$,然后如果 $a$ 不是新建的点的话,$ans \gets ans - \operatorname{Sum}(\textit{ldf}_{a}, \textit{rdf}_{a})$,$b$ 同理。最终我们把 $\text{DFS}$ 序上的 $x$ 和 $y$ 位置分别 $+1$ 就可以了。正确性显然。
按照上面的做法是一个 $\log$ 的,但是通过一些奇技淫巧可以优化成线性,这里不再讨论。
代码实现推荐兔队长的赛时提交,个人认为写的很清晰了。