對矩陣乘法和重鏈剖分有必定了解便可。spa
首先咱們這個題能夠很簡單寫出一個方程,設\(f[x][0]\)爲不選\(x\)時\(x\)子樹內的最大獨立集,設\(f[x][1]\)爲選\(x\)時\(x\)子樹內的最大獨立集,那麼有如下轉移:
\[ f[x][1]=val[x]+\sum_{y \in son[x]}f[y][0] \]class
\[ f[x][0] = \sum_{y\in son[x]}max(f[y][0], f[y][1]) \]總結
咱們轉移到某一個兒子\(y\)的時候,那麼有式子:
\[ f[x][1]=S_1+f[y][0]\\ f[x][0]=S_0+max(f[y][0], f[y][1]) \]查詢
\(S_0,S_1\)表明剩餘的其餘兒子的\(dp\)值之和,顯然\(,S_0,S_1\)的計算與\(y\)無關,咱們從新定義矩陣乘法\(C=A*B\)爲\(C[i][j]=max_{k=1}^K(A[i][k]+B[k][j])\),再把轉移寫成矩陣的形式:di
\[ (f[x][0],f[x][1])=(f[y][0],f[y][1])* \left( \begin{matrix} S_0 & S_1 \\ S_0 & -\inf \end{matrix} \right) \]display
那麼咱們就能夠經過矩陣動態維護\(dp\)了,咱們首先進行樹鏈剖分,令每一個點的矩陣爲從重兒子轉移到自身的矩陣,那麼咱們每當對一個點進行修改的時候,它的實父親的轉移矩陣是不會有變化的,可是每條輕邊會致使一個點的轉移矩陣變化,那麼只有\(\log n\)個點的轉移矩陣發生變化,那麼咱們能夠用線段樹快速查詢出一個點的\(dp\)值,再用它去更新它虛父親的轉移矩陣便可。其中改變是這樣的,定義轉移後的\(dp\)值爲\(F\),那麼:math
\[ S_0=S_0 + max(F[y][1],F[y][0])-max(f[y][1],f[y][0])\\S_1=S_1+F[y][0] -f[y][0] \]play
總結一下就是先記下當前重鏈頂端的\(dp\)值,再修改當前點的轉移矩陣,而後就是求出當前重鏈頂端的\(dp\)值,再更新與這條重鏈經過輕邊相連的上一條重鏈,這樣子複雜度是\(O(2^3n\log^2n)\)。
這個作法本質就是經過把轉移寫成矩陣乘法的形式再利用矩陣乘法的結合律能夠快速算出一段區間的矩陣乘積,這類帶修改的DP只要直接把轉移寫成矩陣形式維護矩陣就比較好作了。