链分治
链分治就是树链剖分。
在需要回答在子树/或结点到根路径查询时,由于 d f s dfs dfs序的连续性,可以用到树链剖分将复杂度降到 l o g 2 n log^2n log2n。
先不考虑具体如何维护每个点的 d p dp dp值,假设转移是 O ( 1 ) O(1) O(1)的,可以用线段树维护,那么修改某个点的 d p dp dp值实际上就是修改了它到根路径上的值,查询答案即为根结点上的值。
在链分治后,只会跳 l o g n logn logn次链,每次链内/链与链交接处都可以 l o g n logn logn修改。
动态DP
查询操作
求树上的最大权独立集的权值大小。
设 f [ x ] [ 1 / 0 ] f[x][1/0] f[x][1/0]分别表示选/不选点 x x x时, x x x子树上的最大权独立集的权值大小,
正常的 D P DP DP转移:
f [ x ] [ 0 ] = m a x y ∈ s o n x ( f [ y ] [ 0 ] , f [ y ] [ 1 ] ) f[x][0]=max_{y\in son_x}(f[y][0],f[y][1]) f[x][0]=maxy∈sonx(f[y][0],f[y][1])
f [ x ] [ 1 ] = v a l x + m a x y ∈ s o n x f [ y ] [ 0 ] f[x][1]=val_x+max_{y\in son_x}f[y][0] f[x][1]=valx+maxy∈sonxf[y][0]
为了达到每次链内/链与链交接处都可以 l o g n logn logn修改,我们显然不能对于每个点逐个儿子的转移,而需要把信息压成重儿子和轻儿子两部分。
设 g [ x ] [ 1 / 0 ] g[x][1/0] g[x][1/0]分别表示不考虑重儿子情况下,选/不选点 x x x时, x x x子树上的最大权独立集的权值大小。
现在的 D P DP DP转移:
f [ x ] [ 0 ] = g [ x ] [ 0 ] + m a x ( f [ s o n x [ 0 ] , f [ s o n x ] [ 1 ] ] ) f[x][0]=g[x][0]+max(f[son_x[0],f[son_x][1]]) f[x][0]=g[x][0]+max(f[sonx[0],f[sonx][1]])
f [ x ] [ 1 ] = g [ x ] [ 1 ] + f [ s o n x ] [ 0 ] f[x][1]=g[x][1]+f[son_x][0] f[x][1]=g[x][1]+f[sonx][0]
似乎可以 O ( 1 ) O(1) O(1)合并了,线性的加和取 m a x max max。
考虑维护连续的一段线性的加和取 m a x max max的方法,我们联想到了矩阵。
上述转移可以仿照 F l o y d Floyd Floyd的形式写成矩阵乘法:
[ f [ x ] [ 0 ] f [ x ] [ 1 ] ] = [ g [ x ] [ 0 ] g [ x ] [ 0 ] g [ x ] [ 1 ] − i n f ] × [ f [ s o n x ] [ 0 ] f [ s o n x ] [ 1 ] ] \left[ \begin{matrix} f[x][0] \\ f[x][1] \end{matrix} \right]= \left[ \begin{matrix} g[x][0]& g[x][0]\\ g[x][1] & -inf \end{matrix} \right]\times \left[ \begin{matrix} f[son_x][0]\\ f[son_x][1] \end{matrix} \right] [f[x][0]f[x][1]]=[g[x][0]