樹鏈剖分的學習理解

2021-08-22 16:40:32 字數 1313 閱讀 2029

【前言】

本文僅為本人學習樹鏈剖分的理解和總結,有誤之處請大佬指點迷津。也有與其他部落格不同或矛盾之處。

【樹鏈剖分】

顧名思義,將樹結構,剖分成鏈狀結構,然後將一條條的鏈拼接成線性結構,然後就可以通過線段樹、樹狀陣列等維護了。

說白了就是在樹上,有些值不好維護,通過樹鏈剖分轉化成乙個序列,而序列就好維護了。

樹鏈剖分做的事情就是把樹對映成乙個序列,讓線段樹去維護這個序列,以達到維護樹的目的。

【剖分方法】

1.概念

重兒子:結點u的子結點中,擁有最大子樹的那個兒子結點。

輕兒子:除了唯一的重兒子,其餘都為輕兒子

重鏈:   從結點u向重兒子延伸下去,所形成的一條鏈

輕鏈:   去掉重鏈,剩下的那些鏈都是輕鏈,一般來說,輕鏈都是孤立的點。

圖中粗邊連線的鏈就是重鏈,其餘為輕鏈。標記紅點的點為重鏈的起點。邊上的數字表示dfs時的順序(一定要重鏈的dfs序連續)。

2.設定陣列

陣列名功能

dep[u]

樹上結點u的深度(根結點為0)

dad[u]

樹上結點u的父結點(假設根結點為本身)

siz[u]

樹上結點u的子樹結點數目(包括u本身)

son[u]

樹上結點u的重兒子

top[u]

樹上結點u的重鏈隊長,即u所在的重鏈以top[u]為起點

rk[u]

樹上結點u對應的序列位置下標

id[ i ]

序列上位置 i 對應的樹上結點編號(基本無實際用處)

3.求出2中的所有陣列

兩次dfs,第一次dfs,求出dep,dad,siz,son,這四個很簡單。第二次dfs求top,rk,id,這裡需要注意dfs優先進入重兒子。

其實rk陣列才是主角,我們按照dfs進行的順序,給樹上點編號,並且讓重鏈的編號都是連續的(dfs2優先進入重兒子的原因),這樣我們就能用線段樹維護這段重鏈了。

/************ 樹鏈剖分 **************/

int dep[max],dad[max],siz[max],son[max];

int top[max],rk[max],id[max];

void dfs1(int u,int pre)

else

} //迴圈結束時,fu-fv在同一鏈

if(dep[u]>dep[v])swap(u,v);

update(rk[u],rk[v],num,1,1,limit);

}

【練習題】

hdu3966  

題解:

樹鏈剖分學習

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

樹鏈剖分學習

之前寫過樹剖的題,但沒有完全理解,現在又無法複述思路了,所以重新學習一下,部分語句參考大神的敘述 一 概念 樹鏈剖分,顧名思義,樹是由一根根樹鏈組成的,我們現在要來把它按鏈來分解掉。我們知道,大部分樹上的問題都是圍繞樹的路徑來做文章,分解成一條條的鏈之後,我們就可以對節點 邊 就行編號了,而同一根鏈...

樹鏈剖分學習

樹鏈剖分其實就是把一棵樹剖分成一條條鏈 重鏈輕鏈 然後用線段樹進行操作維護。複雜度logn 記錄 deep size fa pos bl 陣列 deep深度,size子樹節點個數,pos節點編號,bl所在重鏈頂端節點編號,fa父親編號。例題 bzoj1036 include define inf 1...