「刷题」保卫王国

  动态$dp$的板子题,然而我线性代数太菜写了好几个小时。

  由于我只会树剖的$log^2n$所以跑的也奇慢,不过在一通对拍下终于痛苦$AC$了。

  简单说一下$ddp$的思路。

  按树剖来说的话,就是分离重儿子和轻儿子在$dp$中的贡献,在数据结构中记录非重儿子的信息。

  这样由于我们修改一个点的权值,必然会改变他父链上的点的$dp$值,我们发现这个点作为重儿子的情况下是不需要修改任何信息的,需要修改的仅仅是作为轻儿子的请况,我们发现这样的轻边是$logn$级别的。同时对于父链一条轻边的起点,这个点必然是属于他所属重链的重儿子,那么这条重链非链尾(这个点)的部分均不需要修改,这样修改的次数就是$logn$条的,数据结构维护即可。

  首先考虑这道题的$O(nm)dp$。

  设$dp[x][0/1]$为点$x$选/不选的情况下,子树的点全部被覆盖的最小代价。

  那么有转移:$$dp[x][s]=\begin{cases}&\sum\limits_{t\in son(x)}dp[t][!s]\ s=0&\\&a[x]+\sum\limits_{t\in son(x)}\min{dp[t][s],dp[t][!s]}\ s=1&\end{cases}$$

  这样每次一修改我们就重复这一过程,复杂度就是$O(nm)$的了。

  考虑复杂度瓶颈。

  在于$dp$必须要重复计算每个位置的值,而有很多是没有被修改影响的。

  我们考虑一下一个算法,对于修改的点,发现受他影响的只有他父链上的点,那么可以只做父链上的点的$dp$。

  然而轻松被链式数据卡成$nm$。

  思考一下能不能用数据结构维护这个$dp$。显然不能,这个$dp$暂时不具有结合律。

  尝试线性代数优化,结合树剖也许有不一样的效果。

  拿出矩阵来。

  首先设一个参量$g[x][0/1]$,$ch[x]$为一个节点的重儿子。

  定义:$$g[x][s]=\begin{cases}&\sum\limits_{t\in son(x),t!=ch[x]}dp[t][!s]\ s=0&\\&a[x]+\sum\limits_{t\in son(x),t!=ch[x]}\min{dp[t][s],dp[t][!s]}\ s=1&\end{cases}$$

  维护一个矩阵:$$R[x]=\left[\begin{array}{c}&+\infty\ g[x][0]&\\&g[x][1]\ g[x][1]&\end{array}\right]$$

  维护一个矩阵:$$G[x]=\left[\begin{array}{c}dp[x][0]\\dp[x][1]\end{array}\right]$$

  定义一种矩阵运算:$$A=B*C\ <=>\ a_{i,j}=\min\limits_{k}\{b_{i,k}+c_{k,j}\}$$

  定义单位元:$$I=\left[\begin{array}{c}&0\ +\infty&\\&+\infty\ 0&\end{array}\right]$$

  好,那么根据这种运算我们知道:$$R[x]G[ch[x]]=G[x]$$

  这样可以分离重儿子的贡献,并且$dp$的转移也做到了有结合律,可以用数据结构了。

  线段树维护重链来做到这一点。

  那么对于每一个修改的点,考虑这个点对其轻父链的影响,首先计算出当前点所在重链的矩阵乘积,这个矩阵乘积的后一列就是当前重链顶的$dp$值,这样计算修改前后的差值,这样可以快速的修改轻父链,做到总复杂度$O(nlog^2n)$

猜你喜欢

转载自www.cnblogs.com/Lrefrain/p/11838626.html