LGP4719 [LG TPLT] DDP EasyVer 学习笔记
LGP4719 [LG TPLT] DDP EasyVer 学习笔记
题意简述
给定 \(n\) 个点的树一棵,每个点有点权。\(m\) 次单点修点权,在每次操作之后求出这棵树最大权独立集的权值大小。
\(1\le n,m\le 10^5\)。保证整棵树的点权和始终不大于 \(10^9\)。
做法解析
如果不带修就是 \(\texttt{LGP1352}\)。此不赘述。
但是带修呢?首先我们发现单点修改 \(a_u=x\) 只会改变 \(u\) 到根直链上所有点的 \(\texttt{DP}\) 值。我们最容易想到的就是树剖。剖完之后 \(O(\log n)\times k\) 做修改。
那么对于剖出来的每一段链,我们要怎么做修改呢?如果这条链很长很长,有 \(O(n)\) 那么长,我们总不能 \(O(n)\) 地做修改吧。就是说,上面那个 \(k\) 也得控制在 \(O(\log n)\times k'\) 这个水平(毕竟 \(10^5\) 就是标准的双老葛带常熟的复杂度)。
我们先把 \(\texttt{LGP1352}\) 的转移柿子写一下。定义 \(f_{u,0/1}\) 为不选或选 \(u\) 号点时,\(u\) 子树的最大权独立集。则有:\(f_{u,0}=\sum\max(f_{v,0},f_{v,1})\),\(f_{u,1}=w_u+\sum f_{v,0}\)。
我们发现,如果我们使用这个式子就必须要一步一步推上去。这显然不能接受。现在我们想要让 \(\texttt{DP}\) 的转移满足结合律,我们要怎么做?当然是把 \(\texttt{DP}\) 转移写成矩阵!
首先,以防你忘记了矩阵乘法,下面几张图将展示一个对其最简单的理解:



最后我们就很好理解 \(C_{i,j}=\sum_{k=1}^n A_{i,k}\times B_{k,j}\)(我们在实际应用场景中令先被乘的那个是 \(A\),就这样)。注意矩阵乘法并不满足交换律。所以线段树维护的时候要用右区间的矩阵乘左区间的(因为同一条重链下右区间比左区间对应的原树上结点深度更深)。
上文“先乘”的意思:结果的行数继承先乘的那个矩阵。反之,结果的列数继承后乘的。
不过,广义的矩阵乘法还可以长成别的样子。我们把上面那个矩阵乘法叫做 \(\{+,\times\}\) 矩阵乘法,前面那个“加”意为对所有 \(k\) 的柿子求和,后面那个“乘”意为 \(A,B\) 取出的元素做乘法运算。那么,这题需要怎样的矩阵乘法呢?
我们拿出 \(\{\max,+\}\) 矩阵乘法。这个矩阵乘法也满足结合律(我暂时不会证明)。现在开始造矩阵吧。
当然,我们首先得处理一个 \(g_{u,0/1}\),也即不考虑重儿子的 \(f\) 数组出来(必要性显然,你实际上是从重链往上做的,当然要将重儿子 \(h\) 的结果和轻儿子们的结果分离一下)。于是我们有:\(f_{u,0}=g_{u,0}+\max(f_{h,0},f_{h,1})\),\(f_{u,1}=g_{u,1}+f_{h,0}\)。
然后开造矩阵。我们要造的东西形状如下:
这里后者先乘。外面没套 \(\max\) 就意味着 \(k\) 取 \(1\) 或 \(2\) 结果相同。基于此,我们需要满足:\(f_{u,0}=\max(f_{h,0}+U_{1,1},f_{h,1}+U_{2,1})\),\(f_{u,1}=\max(c+U_{1,2},d+U_{2,2})\)。再加上我们要让 \(U\) 只含 \(g\),所以我们自然有:\(U_{1,1}=U_{2,1}=g_{u,0}\),\(c=f_{h,0}\),\(U_{1,2}=g_{u,1}\)。
最后我们可以写出:
好,现在知道线段树要维护什么了吧。总时间复杂度 \(O(2^3m\log^2n)\)。
代码实现
浙公网安备 33010602011771号