長鏈剖分,也屬於樹鏈剖分的一種方式,但是其與經典的重鏈剖分又不太一樣。
在重鏈剖分中,我們評判兒子重或輕的方式是比較其子樹節點數量。
在長鏈剖分中,我們以子樹中最深的葉節點深度的大小來比較。
其他步驟與重鏈剖分類似,都是兩遍dfs即可解決,都是o(n)的複雜度。
接下來,我們來看兩個長鏈剖分的經典問題.
時間複雜度要求: o(nlogn).
需要技能:
我們利用的性質是:任意乙個點的k級祖先所在鏈的鏈長一定大於等於k。
證明:
1.如果這個點和他的k級祖先在一條鏈上,那麼結論顯然成立。
2.如果不在一條鏈上,那麼一開始這個祖先沒有選擇這棵子樹是因為別的子樹更深,故而所在鏈一定是大於k的,結論仍然成立。
操作步驟
對樹進行長鏈剖分,記錄每個點的鏈頭和深度
倍增預處理出每個點2^n級祖先
如果某條鏈的長度是len,那麼在鏈頭處記錄鏈頭向上的len個祖先,並記錄向下的len個鏈的元素
記錄每個數最高位1是多少
總時間複雜度: o(nlogn)
先利用倍增陣列跳k的最高位的1層,設剩餘層數為k,可以發現
利用之前證明的性質,我們可以發現當前節點所在鏈鏈長一定嚴格大於k。如果鏈頭在當前節點的k級祖先上面,那麼我們利用鏈頭向下的陣列可以o(1)得到答案,否則利用向上的陣列同樣可以o(1) 得到答案。
這個應用的思想十分類似dsu on tree
。
思想是當前結點直接繼承重兒子的資訊,輕兒子資訊暴力統計。
因為長鏈剖分的特殊性,因此這個應用僅限於以深度為下標。
更一般的就只能使用dsu on tree
做到o(nlogn)的複雜度了。
更具體地:
若需求出點x的資訊,首先從重兒子繼承。
因為以深度為下標,因此只需要對陣列進行移位即可。
後面我們會提到移位的實現方法。
接著,輕兒子的資訊暴力合併到當前的資訊中。
時間複雜度o(n)。
分析如下:
每個點x只會暴力統計其所有輕兒子的資訊,而每個輕兒子的資訊大小為該輕兒子所在長鏈長度。
而當遞迴到x的父節點fa(x)時,若xx不是fa(x)的重兒子,則fa(x)會暴力統計大小為x長鏈長度的資訊。
故,每個長鏈只會對轉移的複雜度做一次大小為其長度的貢獻。
因此根據性質1,總時間複雜度為o(n)。
移位的實現方法:
本處僅提到一種實現方式,但方法不只有這一種。
用指標維護動規陣列,在重兒子傳遞給父親時將指標左移/右移一位。(左移還是右移根據轉移方程決定)
而給其他輕兒子分配不相交的記憶體即可。
不難發現,這樣實現的空間複雜度仍為o(n)。
特別注意,這樣實現也有相應的缺點,即若動規的陣列高於一維,那麼陣列是一次性的,不能在完成轉移後查詢中間過程的值。
原因是部分記憶體被共用掉了。
長鏈剖分在維護一些與深度有關的資訊時十分強力有效。
在考慮題目時靈活運用其性質往往可以得到較好的結果。
例題:[bzoj3252] 攻略]
[wc2010]重建計畫
學習筆記 長鏈剖分
處理和深度有關的一些事情 長鏈剖分的 和重鏈剖分一樣。只是重兒子條件不同罷了。之前和沒學一樣。補充 本質是優化dp,dp一維和深度有關 實現有一些類似dsu on tree 長鏈剖分還有乙個操作精髓是繼承長兒子的資訊 通常用指標分配記憶體,使得長兒子資訊更新位置恰好是x的位置偏移一位 共用部分陣列,...
長鏈剖分學習筆記
學這個之前應該要比較熟悉重鏈剖分,推薦一下這篇部落格。我們模擬重鏈剖分,定義每個點所有兒子中,子樹深度最大的點為它的重兒子,那麼整棵樹就被劃分成了一些不相交的重鏈,然後首先就有乙個性質那就是所有重鏈長度和是 o n 級別的,這個東西很顯然,還有乙個性質就是乙個點的k級祖先所在重鏈長度一定大於等於k,...
長鏈剖分學習筆記
終於認真寫一次標題了 因為一些不明原因,之前對 dsu on tree 的理解沒有完全寫出來,在這裡會一起寫,因為兩者極為相似。先來看一下 dsu on tree 和長鏈剖分的對比。dsu on tree 實際上就是重鏈剖分,可以處理很多與子樹有關且不帶修改的題目 離線 複雜度 mathcal nl...