DDP 学习笔记
Part 1
我们定义广义矩阵乘法:
声称矩阵乘法满足结合律,仅需满足 \(\otimes\) 有结合律,且 \(\otimes\) 对 \(\oplus\) 有分配律。
常见的卷积有 \(\min +\) 和 \(\max +\) 卷积;以及图论的邻接矩阵 \(or \ and\) 卷积,表示在 \(k\) 次的意义下,表示点 \(u\) 经过 \(k\) 步是否能到达 \(v\)。
由于矩阵计算的性质,可以通过矩阵乘法刻画 DP 的状态转移。不一定是线性,只需满足广义矩阵乘法的性质即可。
Part 2
以树上最大独立集为例。
若直接跑复杂度爆炸。注意到 \(i\) 到根节点的链上至多出现 \(O(\log)\) 条重链。将轻重儿子分开考虑。
令 \(f_{i,0/1}\) 表示 \(i\) 是/否选取时,\(i\) 的子树内的最大价值;\(g_{i,0/1}\) 表示 \(i\) 的子树中,\(i\) 的重儿子不选的前提下,\(i\) 的子树内的最大价值。令 \(s_i\) 为 \(i\) 的重儿子。
于是可以得出
其形式为 \(\max, +\) 卷积,满足分配律。
令 \(f_{i,0/1}\) 的形式为 \(F(i)\),\(g_{i,0/1}\) 的形式为 \(G(i)\)。
由第一个式子,发现 \(F(i)\) 仅仅和 \(i\) 所在的重链有关,设重链的头为 \(top_i\),重链的尾为 \(end_i\)。发现 \(F(i)\) 就为 \((\prod_{j=i}^{fa_{end_i}} G(j)) \times F(end_i)\)(这里的 \(\prod\) 指在树上的链)。由于重链的性质,\(end_i\) 为叶子结点,则 \(F(end_i) = G(end_i)\)。于是可以得出,\(F(i)\) 为 \(i\) 到 \(end_i\) 所有 \(G\) 的乘积。所以现在 \(F(i)\) 是可以用 \(G\) 取代的,而 \(F\) 本质上也成为了 \(G\) 的中间值,没有实质性作用。只需快速得出 \(G(i)\) 即可。
Part 3
接下来是所有 DDP 都要思考的关键问题。
我们发现 \(G\) 的修改仅存在于轻边连接的深度较小的节点,记这个点为 \(i\);修改的轻儿子记为 \(j\)。要想修改 \(G(i)\),就必须知道它的轻儿子的 \(F\)。由于 \(G\) 的求法是对 \(F\) 具有可减性的,所以可以先求出 \(F(j)\) 原值,在 \(G(i)\) 中减去,再加上 \(F(j)\) 的新值。考察修改 \(i\),发现其实是 \(G(i)\) 中的 \(val_i\) 发生了改变;于是在求原值后,加上新值前更新即可。
至此,已经完成了 DDP 的核心内容。具体的,要实现以下的操作:
- 线段树支持单点修改,维护区间乘积(矩阵)。
- 重链剖分。
实现不难。复杂度为 \(O(n \log^2 n \times w)\),其中 \(w\) 为矩阵运算的常数。

浙公网安备 33010602011771号