學習總結 樹鏈剖分

2022-06-19 18:27:15 字數 2658 閱讀 3967

對於解決一類樹上的問題,可以將樹上問題轉化為區間上問題求解。樹鏈剖分是指將

樹剖成鏈以解決一些樹上難以解決的問題。

那麼,問題來了,應該按照怎樣的規則將樹剖分?

本文中的樹鏈剖分按照"重鏈"進行剖分。

首先要了解幾個概念:

對於乙個節點,定義:

重兒子:該節點的所有子節點中,包含子節點節點數目最大的節點(乙個節點最多乙個)

輕兒子:該節點除重兒子以外的子節點

重邊:連線該節點與重兒子的邊

輕邊:連線該節點與輕兒子的邊

重鏈:由重邊相接組成的鏈

輕鏈:由輕邊相接組成的鏈

樹鏈剖分一種剖分方式是重鏈剖分,使重鏈上的節點在重新編號後成為連續的一段區間,以方便維護。

按照"重鏈"剖分其實是一種啟發式剖分。此外,還有按照"長鏈"剖分。

援引巨佬部落格中的內容:

樹鏈剖分目的:樹路徑資訊維護。

將一顆樹劃分成若干條鏈,用資料結構去維護每條鏈,複雜度\(\theta(n\log n)\)

劃輕重鏈目的:為了讓鏈上節點的編號連續。

我們在用線段樹維護鏈的時候,如果節點編號不連續,那麼就無法用線段樹。

第一步,遍歷整棵樹,將每個節點,每條邊的資訊處理出來。

需要處理的資訊有:

\(f[x]\):記錄節點\(x\)的父節點

\(siz[x]\):記錄以節點\(x\)根的子樹大小

\(son[x]\):記錄節點\(x\)的重兒子

\(d[x]\):記錄節點\(x\)的深度

\(top[x]\):記錄\(x\)所在的重鏈的頂端節點(即\(x\)所在重鏈上深度最淺的節點。如果\(x\)不在重鏈上,那麼\(top[x] = x\))

\(id[x] = y\):記錄節點\(x\)的新編號\(y\)

\(rak[y] = x\):記錄新編號\(y\)對應的節點\(x\)

對於前四個資訊,很容易維護,只需要從根節點遞迴遍歷整棵樹即可。**如下:

void dfs1(int x, int fa, int deep)

return ;

}

對於後面兩組資訊,我們需要解決的問題是,如何保證重鏈上的節點有連續的一段編號?

聯想到\(dfs\)序的性質,只要每次遞迴遍歷的時候優先遍歷重兒子,給其編號,就能保證重鏈上的節點有連續的一段編號了。

對於輕兒子,我們可以將其看作只有乙個節點的重鏈。**如下:

void dfs2(int x, int t)

return ;

}

至此,整棵樹剖分已完畢。我們得到了乙個序列,不難**這個序列的性質。

由於我們是按照求\(dfs\)序的方法對節點編號,因此,這個序列具有\(dfs\)序的特點。

特點一:對於一棵子樹,它所有節點的編號是連續的。

同時,由於我們優先為重兒子編號,該序列還具有的特點是:

特點二:對於一條重鏈,它所有節點的編號是連續的。

眾所周知,\(lca\)可以使用倍增求解。時間複雜是預處理\(\theta(n\log n)\)加上每次詢問\(\theta(\log n)\)。

如果使用樹鏈剖分求解\(lca\),可以更高效。那麼,如何運用呢?

\(lca\)的倍增方法是將兩個節點根據預處理出來的陣列不斷地向上

樹鏈剖分也預處理了乙個指向\(x\)祖先的陣列\(top[x]\),是否可以仿照\(lca\)的模式,不斷向上呢?

答案顯然是可以的。

如果\(x\),\(y\)一直向上走,肯定會走到乙個公共節點。為了避免\(x,y\)"擦肩而過",每次我們只讓其中乙個向上走。

怎麼走呢?如果\(x,y\)不在一條重鏈上,那麼就讓深度較深的節點走到該條重鏈頂端的父節點,交錯著走,直到\(x,y\)在一條重鏈上。

如果\(x,y\)在一條重鏈上,那麼它們的\(lca\)顯然是它們兩個中深度較淺的節點。

可以證明,剖分出來的路徑不超過\(\theta(\log n)\)條,因此,樹鏈剖分求\(lca\)的時間複雜度是:預處理\(\theta(n)\)加上查詢\(\theta(\log n)\)

設這條路徑的兩個端點分別為\(x,y\)。由樹的性質可以知道,\(x,y\)之間只存在唯一的一條路徑。這條路徑是\(x\to lca(x,y)\to y\)。

因此,我們只需要在求\(lca(x,y)\)的同時,將經過的所有重鏈進行維護即可。

假設用線段樹進行區間維護,那麼時間複雜度為:

線段樹區間修改複雜度\(\theta(\log n)\),樹剖求\(lca(x,y)\)時間複雜度\(\theta(\log n)\),總時間複雜度\(\theta(\log^2n)\)

留坑待補...

樹鏈剖分總結

樹鏈剖分思想不是很複雜。首先給出幾個定義吧 其核心思想就是,將一棵樹拆成多條鏈,然後對於每一條鏈,就用資料結構去維護。有個不會證明的性質,就是如果將一顆樹拆成多條重鏈和輕邊,那麼重鏈的個數不會超過 log 2n 輕邊的邊數也不會超過 log 2n 因為這個性質,很多操作我們可以很高效地完成。這個之後...

樹鏈剖分總結

把樹剖成鏈再操作 部落格安利 維護7個不同陣列,通常和線段樹一起使用 1 模板題 p3384 模板 樹鏈剖分 p3178 haoi2015 樹上操作 p2590 zjoi2008 樹的統計 p2146 軟體包管理器 p2420 讓我們異或吧 2 應用題 p3950 部落衝突 p3038 牧草種植 1...

樹鏈剖分學習

樹鏈剖分 看了學習了樹鏈剖分 適用於在樹上的路徑操作。關鍵在於重鏈的構造,把它表示到了資料結構上的連續區間,降低了複雜度。主要操作步驟實際上有三個部分 1 構造重鏈 2 如何維護資料 3 分解為輕重鏈的查詢與修改 include include include include define n 10...