洛谷 P5291 [十二省联考2019]希望

洛谷 P5291 [十二省联考2019]希望

https://www.luogu.com.cn/problem/P5291

https://www.luogu.com.cn/problemnew/solution/P5291

一个有 \(n\) 个节点的树,一共有 \(k\) 个救援队,每个救援队有一个救援范围,即一个连通块 \(s_i\)

我们称一个节点 \(u\) 可被第 \(i\) 个救援队到达当且仅当

  1. \(u \in s_i\)
  2. \(\forall v \in s_i, dis(u, v) \le L\)

求有多少方案 \(\{ s_1, \cdots, s_k \}\) 满足存在一个节点可被所有救援队到达

两种方案不同当且仅当存在 \(i\) , 使得 \(s_i \not= s'_i\)

答案对 \(998244353\) 取模

\(1 \le n \le 10^6\)

\(0 \le L \le n\)

\(1 \le k \le 10\)

Tutorial

由于对于一种合法的方案,可以选择的点构成了一个连通块,我们可以利用树上 点数-边数=1 这一特点,将对于每个连通块统计答案转化为对于每个点和边统计答案.

\(f(u, i)\) 表示 \(u\) 的子树中包含 \(u\) 且所有点距离 \(u\) 不超过 \(i\) 的连通块个数 +1

\[f(u, i) = 1 + \prod_{v \in son(u)} f(v, i - 1) \]

\(g(u, i)\) 表示包含 \(u\) 且不包含 \(u\) 子树中的点且所有点距离 \(u\) 不超过 \(i\) 的连通块个数

\[g(u, i) = 1 + g(fa, i - 1) \prod_{v \in son(fa), v \not = u} f(v, i - 2) \]

每个点的贡献为

\[((f(u, L) - 1)g(u, L))^k \]

每条边的贡献为

\[((f(u, L - 1) - 1)(g(u, L) - 1))^k \]

直接DP的复杂度为 \(O(nL)\) ,接下来我们考虑如何优化计算 \(f,g\) 的过程

由于第二维与深度有关,所以考虑使用长链剖分优化.

\(f\) 的优化就是经典问题 , 需要进行所有值 +1 的操作,维护一个加法标记.

对于 \(g\) 我们需要从上到下更新,对于 \(u\) 节点,我们需要知道的只有 \(g(u, L)\) ,所以我们只需要保留 $g(u, L - len(u) + 1) $ 到 \(g(u, L)\) 的DP值,其中 \(len(u)\) 表示 \(u\) 出发的长链的点数.

对于上边 \(g\) 的转移中的 \(\prod\) 的部分,其实也就是 \(\dfrac {f(fa, i - 1) - 1}{f(v, i - 2)}\) 但是 \(f(v, i - 2)\) 可能等于 \(0\) ,我们可以看作 \(f(v, i - 2)\) 序列的一个前缀和一个后缀的乘积.

一个前缀的积可以表示为在计算 \(f\) 的过程中某一时刻的 \(f(fa, i - 1)\) ,为了得到这个值,我们可以在计算 \(f\) 每次转移时纪录修改过的值,就可以实现回溯.

一个后缀的积,可以在求 \(g\) 的时候采用与计算 \(f\) 时相反的顺序,类似维护 \(f\) 的方法维护.

注意由于 \(f,g\) 的定义中都有 不超过 ,以 \(f\) 为例, 设 \(l_u = len(u) - 1\),实际上 \(f(u, k), k > l_u\) 也是有值的,且等于 \(f(u, l_u)\) , 因此转移时 \(f(u)\) 的一段后缀会乘上 \(f(v, l_v)\)

\(f(v, l_v) = 0\) 时相当于将一段后缀赋值,可以维护 \(pos\) 表示 \(f(v, k), k \ge pos\) 的值都等于 \(0\)

\(f(v, l_v) \not=0\) 时,由于后缀之外的部分是 \(O(l_v)\) 的,所以我们可以将那段前缀乘上 \(f(v, l_v)\) 的逆元,然后维护一个乘法标记.

由于 \(n \le 10^6\) ,所以我们想办法去掉求逆元带来的 \(O(\log n)\) , 发现我们只需要求出所有 \(f(u, l_u)\)\(u\) 子树中所有包含 \(u\) 的连通块的个数, 可以用类似求阶乘逆元的方法求出这 \(O(n)\) 个数的逆元.

总时间复杂度 \(O(n)\)

Summary

首先利用 点数-边数=1 将统计连通块转化为统计点.

写出DP方程后,发现第二维与深度有关,于是考虑长链剖分.

由于只关心 \(g(u, L)\) , 所以从上到下的部分也可以使用长链剖分

通过纪录每次修改的位置,来实现回溯.

对于全局加,后缀乘,后缀赋值,利用标记在复杂度不劣化的条件下维护.

\(n\) 个数逆元可以用类似求阶乘逆元的方法做到 \(O(n)\)

posted @ 2020-06-25 21:30  LJZ_C  阅读(165)  评论(0编辑  收藏  举报