動態dp學習筆記


\(noip\)考了,趕緊補一發。

不得不說網上的題解還是不錯的ljq的代碼吼啊

  • 一開始看的博客
  • 模板
  • 其實我感覺看博客不如看別人優秀的代碼來的快
  • 朴素\(dp\)的想法就是\(f_{i,01}\)表示當前點\(i\)選還是不選。
  • 而動態\(dp\)的思想就是,把\(dp\)方程寫成矩陣乘法的形式,然后用數據結構來維護區間矩陣乘積。

首先是樹鏈剖分的思想

  • 講一講自己的感想
  • 首先我們為了使得\(f\)帶修改,引入了樹鏈剖分套線段樹維護矩陣進行\(dp\)
  • 但是這樣我們是無法直接維護\(f\)的,因為剖分的思想是重鏈不會超過\(log\)次划分。
  • 假設我們現在可以一次性跳完整個重鏈,那么問題就變成了是否可以從重鏈頂跳到上一個重鏈
  • 於是我們引入新數組\(g\),表示不算當前重鏈的所有貢獻。
  • 那么我們只需要維護\(g\),每次修改就直接把整個重鏈的\(g\)全部\(\prod\)起來,然后修改父親的\(f\)
  • 此時我們發現,不是每個地方的\(f\)都是有意義的。
  • 首先我們知道每個位置的\(g\),然后用線段樹維護他。
  • 維護\(g\)的原因是我們可以通過線段樹優化\(dp\)轉移使得在\(log\)的時間內得到一段的\(g\)卷積。
  • 所以我們只知道每個鏈頂的\(f\)值,而並不關心每個點的\(f\)
  • 那么問題就簡單多了,對於每次修改,我們只需要修改當前點的\(g\),然后\(\prod\)到鏈頂的\(f\),再用當前的\(f\)更新父親的\(g\),重復這個操作。
  • 實際上我們又給出了\(f\)的新定義,即\(f=\prod g\).
  • 總結一下就是:
  • 個人認為動態\(dp\)的思想在於整體考慮一整個重鏈的\(dp\)轉移
  • 然后再把這個重鏈的\(dp\)轉移貢獻給鏈頂父親
  • 那么在實際設計狀態的時候,形如\(g_{i,j}\)表示\(i\)點不考慮重兒子的\(dp\)值。
  • 然后根據狀態轉移方程一次性考慮一整個重鏈
  • 這樣的話,我們在修改操作的時候,就只需要考慮鏈與鏈之間的關系了。
  • 至此,我們得到了一個\(O(4*q*log^2n)\)的做法。

但是這樣還是不夠優秀

  • 我們選擇更加優秀的\(lct\)維護矩陣信息。
  • 優秀博客
  • 不會lct來這里moflash
  • 此時的\(f\)含義為\(splay\)整個的\(g\)卷積,\(g\)表示虛樹\(dp\)和。
  • 那么\(splay\)就維護了整個實鏈的\(dp\)值。
  • 重點說\(access\)……
  • 轉到根,換兒子,更新信息,前操作點切換為輕邊所指的父親,轉1。
  • 因為除此之外全是模板。
  • 假設當前實鏈頂端結點是\(y\),它爹是\(x\),我們要做的就是把\(x\)\(splay\)上的右兒子設置為\(y\)。這對於我們維護的虛子樹信息而言有兩個影響:
  • 原來\(x\)的右兒子變成了虛的,相當於多了一棵虛子樹。
  • \(y\)由虛的變成了實的,相當於少了一棵虛子樹。
  • 另外這個\(LCT\)有點特別:它既不\(L\)也不\(C\),所以我們不需要翻轉標記,不需要\(pushdown\),不需要\(makeroot\)什么什么的。
  • 至此,我們得到了一個\(O(4*q*logn)\)的做法。
  • 至於為什么復雜度更加優秀,是因為樹剖要一條鏈一條鏈往上,一邊改一邊查,而\(LCT\)只要簡單粗暴地\(access\)一下即可。
  • 在區間問題中,樹剖加線段樹是將鏈進行分治從而提取了很多段區間分別分治,但是\(lct\)\(splay\)的優勢在於可以動態快速提取出整個區間。
  • \(lct\)相比於樹剖,其實是避開了鏈分治的過程,也就省去了一個\(log\)的時間復雜度。
  • 至於實現過程,我們一開始不需要建所有的\(splay\),可以認為一個\(splay\)就只有一個點本身,也就是所有的邊都是虛的。

但是問題在於,我好像忘了\(lct\)怎么打了

。。。。。
先咕咕,等停課了再說。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM