- 如果真的在图上跑算法,那么光建图复杂度就 O ( n 2 l o g n ) O(n^2logn) O(n2logn)了,这显然不可行。所以一定要把 在图上的操作 转换成 在树上的操作
- 在图上删去点u,相当于在树上删去u到根节点的链,并把u的整棵子树删掉
- 如果我们枚举算法可能产生的所有过程,然后再去求每个过程对应的删点次数,那么光枚举过程就已经可以T爆了
- 所以我们只能枚举删点次数,然后求出该删掉次数对应多少种过程
- 这可以用树形DP实现,时间复杂度 O ( n 3 ) O(n^3) O(n3)
- 可以想到用生成函数进一步优化,即用次数来代表删点次数,系数来代表可能过程种数,这样合并两棵子树时直接用NTT把两棵子树的多项式乘起来即可
- 这样会产生两个问题:
-
代码中每一步合并乘的 C j + k k C_{j+k}^{k} Cj+kk怎么办?
-
NTT的时间复杂度是 O ( n l o g n ) O(nlogn) O(nlogn) ( 这 里 n 指 多 项 式 的 最 高 次 数 ) \color{Red}(这里n指多项式的最高次数) (这里n指多项式的最高次数),这样总时间复杂度就是 O ( n 3 l o g n ) O(n^3logn) O(n3logn),怎么还变大了?
就是这两个问题让我在考场上没有继续写下去
- 对于第一个问题,我后来想到,其实不一定要在DP过程中乘 C j + k k C_{j+k}^{k} Cj+kk,DP完后再统一乘 ( 删 点 次 数 ) ! (删点次数)! (删点次数)!来定序也是可行的
- 对于第二个问题,在更新u时,直接用 分治NTT 把u的所有儿子上的多项式 一起 乘起来,不要那么傻逼想着用NTT一个接一个乘
这样时间复杂度降为 O ( n 2 l o g 2 n ) O(n^2log^2n) O(n2log2n),但还是会T - 题目的时间复杂度很大程度上取决于NTT时多项式的最高次数,而多项式次数与删点次数有关,所以考虑一下我们最多能删几个点
- 发现所选的要删的点满足如下规律:所选的任意两个点都不互为祖先关系,且从根到每个叶子的路径上都恰好有一个被选择的点
- 即 u 点 的 多 项 式 的 最 高 次 数 < = u 子 树 内 叶 节 点 的 个 数 \color{Red}u点的多项式的最高次数<=u子树内叶节点的个数 u点的多项式的最高次数<=u子树内叶节点的个数,进一步地,因为每个节点的多项式最高次数至少为1,所以 u 点 的 多 项 式 最 多 是 ( u 子 树 内 叶 节 点 个 数 ) 个 多 项 式 相 乘 的 结 果 \color{Red}u点的多项式最多是(u子树内叶节点个数)个多项式相乘的结果 u点的多项式最多是(u子树内叶节点个数)个多项式相乘的结果
- 设 l e a f u leaf_u leafu表示u的子树中叶子的个数,则在u点分治NTT的时间总和 < = l e a f u ( l o g 2 l e a f u ) <=leaf_u(log^2leaf_u) <=leafu(log2leafu),整道题的总时间 < = ∑ u = 1 n l e a f u ( l o g 2 l e a f u ) <=\sum_{u=1}^{n}leaf_u(log^2leaf_u) <=∑u=1nleafu(log2leafu)
- 考虑两种极端情况,一种是菊花图,一种是一条很长的树链,上面随机的挂上一些类似菊花图(深度小但点度数大)的子树
- 按照上面的做法,菊花图的时间复杂度可以做到 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n),树链的时间复杂度却逼近 O ( n 2 l o g 2 n ) O(n^2log^2n) O(n2log2n)
- 我们考虑给树链换一种做法:
枚举在链上删了哪个点,这样一来整条链和被删点的子树都会被删除,而被删点上方的子树不会被删除,并且相互独立了。
因此,如果链上的点的多项式为 F 1 ( x ) , F 2 ( x ) , F 3 ( x ) . . . F_1(x),F_2(x),F_3(x)... F1(x),F2(x),F3(x)...(按点深度由浅到深编号),那么最后求出这条链的多项式为: F 1 ( x ) + F 1 ( x ) F 2 ( x ) + F 1 ( x ) F 2 ( x ) F 3 ( x ) . . . F_1(x)+F_1(x)F_2(x)+F_1(x)F_2(x)F_3(x)... F1(x)+F1(x)F2(x)+F1(x)F2(x)F3(x)...
用分治NTT做,总时间 < = l e a f 1 ( l o g 2 l e a f 1 ) <=leaf_1(log^2leaf_1) <=leaf