前言
想象我在口胡三樣我都不熟悉的東西並嘗試稱之為“學習筆記”。
其實不過是我自己對於它的一點小理解,甚至可能是錯誤的!
無所謂,口胡!口胡!口胡!口胡!口胡!
一些備註
\(dfn_u\) 為點 \(u\) 的 dfn 序,\(nfd_i\) 表示第 \(i\) 個 dfs 到的點是啥(前者的反陣列)
dfs 序求 lca
這個很簡單,想象把點按照 dfs 序重排後求 lca,設兩點為 \(u≠v\),則 lca 為:
它們 dfs 序區間內深度最小的點的父親。
這個 ST 表搞一下即可 \(O(1)\) 查詢 lca!
證明:由於 \(u,v\) 必然分別在 lca 的兩個子樹中間,想象過程中必然存在一個跳越子樹的過程,跳到新的子樹的根,其父親就是 lca。
(想象這裡有圖片)
相應的也有這樣的結論:
取 \(u,v\) 間(dfs 序上)所有的相鄰點對的 lca,深度或者 dfs 序最小的就是了。
證明同理,想象中間跳子樹的過程。
後面這個沒啥直接用處但是等會要用。
假的,它告訴我們:dfn 序上 lca 和 min 的性質較相似。
虛樹
想象一類樹形問題,每次只取出樹上一小部分點進行詢問,詢問次數和點總和皆是 \(O(n)\)。
此時不能對整棵樹處理,只能取出他們中的一部分點建樹,這就是虛樹了。
但是隻用給出的 \(k\) 點建樹是不夠的,下圖這樣的資訊就儲存不下來了:
(想象這裡有圖片)
那麼我們還應該保證它們的所有 lca 都在虛樹上。
然後根據前面結論 2,你只需要取出 dfn 上所有相鄰點對的 lca(共 \(k-1\) 個),加上一個根節點,共 \(2k\) 個點就行了。
然後具體建邊方法很多,我比較喜歡按尤拉序排序的方式。
這個後面再來補充一下!
樹分塊
雖然說,樹分塊的建樹過程模板是 P2325 [SCOI2005] 王室聯邦,但是我從這個角度切入樹分塊就糊塗了,可能是我太菜!
其實樹分塊的理解方式是:
選出一些點 \(a\),建一棵虛樹,並把虛樹上所有點視為 關鍵點,此時我們發現,任意一條關鍵點上的邊,對應著原來樹上這兩個點之間的路徑和一些小枝枝(伸不出去的)。
這棵樹被叫做原樹的伸縮樹。
那麼此時就發現一條原樹上的路徑變成了現在三個部分:
\(u\) 到某個關鍵點 + 伸縮樹上兩個關鍵點之間的路徑 + 關鍵點二 到 v 的路徑
那麼這看起來很像分塊“大段維護,區域性樸素”的思想,所以我們只需要讓伸縮樹上每條邊對應的原樹邊集儘量平衡就行了。
一般來說平衡應該是 \(B=\sqrt{n}\),如何達到這個平衡呢?
講兩個方法!
隨機撒點
是的!隨機撒 \(O(B)\) 個點建出虛樹(當然他們的 lca 也是要包含的),對於大多數問題來說,只包含對於鏈的詢問,不需要特別的性質(比如板子題就不需要了),這個夠用了。
Top Cluster
想象回到 P2325 [SCOI2005] 王室聯邦,現在來講一下這道題目的做法:
dfs 保證每個子樹只剩下殘餘的 \(<B\) 個點,那麼簡單合併,每當超過了 \(B\) 個就把他們視作一個新的塊,最後必然剩下 \(<B\) 個點視作新的殘餘子樹,遞迴上去解決問題。
就搞定了。
但是直接這樣發現每個塊有不止兩個向外連的節點,並不符合樹分塊的伸縮樹性質。
有兩個解決方案:第一個,把這個塊建出虛樹,虛樹上每一條邊都改成一個新塊,就行了,現在每個塊只有 \(2\) 個關鍵點了。
第二個,直接分的時候,如果加入之後產生了第三個關鍵點,就不加了,直接把當前的點成一塊。
這兩個做法其實差不多的,而且可以證明這樣分是平衡的,但是我不會證明。
後記
圖還沒搞,先發布吧。