對矩陣乘法和重鏈剖分有一定了解即可。
首先我們這個題可以很簡單寫出乙個方程,設\(f[x][0]\)為不選\(x\)時\(x\)子樹內的最大獨立集,設\(f[x][1]\)為選\(x\)時\(x\)子樹內的最大獨立集,那麼有以下轉移:
\[f[x][1]=val[x]+\sum_f[y][0]
\]\[f[x][0] = \sum_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(a[i][k]+b[k][j])\),再把轉移寫成矩陣的形式:
\[(f[x][0],f[x][1])=(f[y][0],f[y][1])* \left( \begin s_0 & s_1 \\ s_0 & -\inf \end \right)
\] 那麼我們就可以通過矩陣動態維護\(dp\)了,我們首先進行樹鏈剖分,令每個點的矩陣為從重兒子轉移到自身的矩陣,那麼我們每當對乙個點進行修改的時候,它的實父親的轉移矩陣是不會有變化的,但是每條輕邊會導致乙個點的轉移矩陣變化,那麼只有\(\log n\)個點的轉移矩陣發生變化,那麼我們可以用線段樹快速查詢出乙個點的\(dp\)值,再用它去更新它虛父親的轉移矩陣即可。其中改變是這樣的,定義轉移後的\(dp\)值為\(f\),那麼:
\[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]
\] 總結一下就是先記下當前重鏈頂端的\(dp\)值,再修改當前點的轉移矩陣,然後就是求出當前重鏈頂端的\(dp\)值,再更新與這條重鏈通過輕邊相連的上一條重鏈,這樣子複雜度是\(o(2^3n\log^2n)\)。
這個做法本質就是通過把轉移寫成矩陣乘法的形式再利用矩陣乘法的結合律可以快速算出一段區間的矩陣乘積,這類帶修改的dp只要直接把轉移寫成矩陣形式維護矩陣就比較好做了。
DP(動態規劃)學習筆記
揹包問題 01揹包每件物品最多使用一次 完全揹包每件物品有無限個 多重揹包每種物品最多有si個 存在樸素版和優化版 分組揹包沒組最多只能選 1 個 dp優化 對dp方程進行等價變形 dp最重要的就是公式推導 對於當前狀態的計算 要滿足兩個條件 不重 不漏 最簡單的01揹包 d p i j ma x ...
總結 動態DP學習筆記
學習了一下動態dp 首先乙個顯然的 o nm 的做法就是每次做一遍樹形dp 這也是我在noip考場上唯一拿到的部分分 直接考慮如何優化這個東西。簡化一下問題,假如這棵樹是一條鏈,那就變得很簡單了,可以直接拿線段樹維護矩陣加速。可是如果每個點不止有乙個兒子呢?我們首先樹剖一下。設 g i 0 sum ...
學習筆記 動態規劃 I 初識DP
更新日期 2018 3 16,2018 12 03 動態規劃,簡稱dp dynamic programming 簡介1簡介2 動態規劃十分奇妙,它可以變身為記憶化搜尋,變身為遞推,甚至有時可以簡化成乙個小小的算式。動態規劃十分靈活,例如 noip2018 pj t3 擺渡車 寫法有很多很多,但時間 ...