點分治是一種樹分治算法(昨天聽了清華大佬Ryz的課,感覺這個人講的還可以,雖然后面有蠻多沒聽懂,比如再套一些七里八里的數據結構)
在解決樹上路徑滿足某種屬性的數量統計方面有着很大的作用
點分治的基本思想如下:
考慮到樹上的路徑對於一個點來說只有兩種情況:一是經過這個點,二是不經過這個點
對於不經過這個點的情況我們可以直接往下遞歸處理,主要問題就是解決經過這一個點的路徑
我們知道:如果一條路徑要經過這個點,那么他必然是由兩條在這個點不同子樹中到這個點的路徑組合而成(這句話真的很重要)
對於這個問題一般又有兩種思想:
1.運用容斥的思想,先把這個節點getdeep的時候搞出來的東西不管是否經過這個點(即不在同一子樹)全部都計算,然后在減去子樹中(即在同一子樹)的這些答案
這樣減剩下就是經過這個點的答案了(參考 樹上的點對以及聰聰可可以及呂欣大爺的c題)
2.類似動態點分治的想法,我們直接對於每個點的子樹的一個一個的做(組合或更新);比如說經常用一些堆,單調隊列(貌似還有平衡樹???)這些東西來實現子樹貢獻合並(參考所有動態點分治)
動態點分治:
相當把重心拿出來重新構了一個新的樹型關系(可以理解為線段樹,每個節點的性質真的跟線段樹很像)
每個重心所管轄的就是他能getdeep的那一片連通塊,然后每個重心額外記一個上層重心即可
這樣有什么好處呢???
我們發現修改的話,這個被修改的點只會影響該點上層的所有重心(log個)
查詢關於某個點的信息時,也只要不斷的往上跳上層重心進行查詢(log次)
那么這樣的復雜度就很能夠接受,至於答案的統計,我們就通過上面說的第二種統計答案的方法進行統計即可
具體實踐參考 qtree5,開店,捉迷藏,重建計划等等,這一類問題統計答案的方法千變萬化,就像線段樹一樣有很多不同的方法
所以一定要好好理解,然后靈活運用,點分治這個算法(or數據解構)其實真的挺有用的
再補充一下關於處理經過一個點的路徑的降低轉移復雜度的方法:
如果關於一個點的路徑的統計是O(size)的那么復雜度是n*logn
如果關於一個點的路徑的統計是O(log*size)的那么復雜度是n*logn^2
上兩種復雜度都是可以接受的,如果再高的話就只得自求多福
有一些人生經驗(世間萬物皆套路...):
1.跟倍數統計相關:開桶
例:聰聰可可的桶和lx的c題的桶
2.如果發現主要是由於某個值的無序性導致無法確定某個值使得無法快速轉移,那么就考慮能否sort后實現O(size)轉移
例:樹上的點對(權值和排序后線性掃),開店(按年齡排序后提取前綴和),呂欣的c題(按最大值排序后依次加入)
3.統計一些最值之類的東西:開堆(並考慮取最優和次優的組合之類的)
例:捉迷藏(取子樹最優+次優合並),qtree5(堆維護最小值)
4.單調隊列(做得少...)
例:重建計划(單調隊列維護[L,R]間權值和最大的路)
