樹鏈剖分小結

2021-07-25 22:11:02 字數 2362 閱讀 1768

寫在前面:樹鏈剖分是一種高效的資料結構,它的作用是將一棵點權樹(一定要是點權樹)拆分成鏈,然後用各種方法來高效解決問題。

樹鏈剖分就是以一種方式遍歷樹,將原來的樹該成一條鏈,,然後對這條鏈進行各種高效的操作。

這種方式就是優先遍歷最大的子樹,我們還是嚴格的從定義學起。

定義:

重兒子:siz[u]為v的子節點中siz值最大的,那麼u就是v的重兒子。

輕兒子:v的其它子節點。

重邊:點v與其重兒子的連邊。

輕邊:點v與其輕兒子的連邊。

重鏈:由重邊連成的路徑。

輕鏈:輕邊。

輕重邊有幾個性質:

性質 1:如果(u, v) 為輕邊,則 size(v)  size(u)/ 2 。

證明:設 size(v)  size(u)/ 2 ,則 size(v) 必然比其他兒子的 size 要大,那麼(u, v)必然為重邊,與(u, v) 為輕邊矛盾。

性質 2:從根到某一點 v 的路徑上的輕邊個數不大於 o(log n) 。

證明:v 為葉子節點時輕邊個數最多。

由性質 1 可知,每經過一條輕邊,子樹的節點個數至少比原來少一半,所以至多經過 o(log n) 條輕邊就到達葉子節點了。

性質 3:我們稱某條路徑為重路徑(鏈),當且僅當它全部由重邊組成。那麼對於每個點到根的路徑上都不超過 o(log n) 條輕邊和 o(log n) 條重路徑。證明:顯然每條重路徑的起點和終點都是由輕邊構成,而由性質 2 可知,每個點到根節點的輕邊個數為 o(log n) ,所以重路徑個數也為 o(log n) 。

同時我們也容易發現,乙個點在且只在一條重路徑上,而每條重路徑一定是一條從根結點方向向葉結點方向延伸的深度遞增的路徑

輕重邊剖分的過程可以使用兩次 dfs 來實現,有時為了防止遞迴過深棧溢位,也會使用bfs 的方法來進行剖分。

在這裡,當然有很多陣列,現在我來分別介紹它們的作用:

top陣列,用來儲存當前節點的所在鏈的頂端節點

son陣列,用來儲存重兒子

dep陣列,用來儲存當前節點的深度

fa陣列,用來儲存當前節點的父親

tid陣列,用來儲存樹中每個節點剖分後的新編號

siz陣列,用來儲存以x為根的子樹節點個數

考慮如何將一條路徑(u, v) 拆分為若干條重路徑:實際上這個過程就是乙個尋找最近公共祖先(lca)的過程。

考慮暴力的做法,我們會選擇u, v 中深度較大的點向上走一步,直到u - v 。現在有了重路徑,由於我們記錄了重路徑的頂部結點top[x],還記錄了每個點在序列中的位置,因此我們不需要一步步走。首先我們找出u, v 中top 深度較大的點,假設是u ,則我們可以直接跳到 fa[top[u]]處,且跳過的這一段,在序列中是一段區間,若我們按照深度從小到大來儲存點,則這段區間為:pos[top[x]], rank[x]。當u, v 的top 相同時,說明它們走到了同一條重路徑上了,這時它們之間的路徑也是序列上的一段區間,且u, v 中深度較小的那點是原路徑的 lca。這樣我們就可以將給出的任意路徑拆分成若干條重路徑,也就是若干個區間,並用線段樹等資料結構處理操作。

實現:

#include#include#include#includeusing namespace std;

const int maxn=300000;

struct treenode[2*maxn];

int first[maxn],last[maxn],nxt[maxn],a[maxn],w[maxn],tid[maxn],e[maxn],top[maxn],rank[maxn],size[maxn],r[maxn],tt[maxn],father[maxn],n,m,k,frog,x,y,g,i,s,tot,z;

void add(int x,int y)

void dfs(int u,int fa)

}void dfs2(int u,int head)

for(i=first[u];i>0;i=nxt[i])

if(size[a[i]]size[mson])mson=a[i];

dfs2(mson,head);

e[u]=e[mson];

for(i=first[u];i>0;i=nxt[i])

if(size[a[i]]}int main()

樹鏈剖分小結

樹鏈剖分,簡單的說,其實就是把一棵樹拆成很多條鏈,然後變成乙個序列,這樣就可以把樹上的問題轉換成簡單的區間問題,而區間問題我們可以用線段樹和樹狀陣列等等資料結構來維護。首先是一些必須知道的概念 重結點 子樹結點數目最多的結點 輕節點 父親節點中除了重結點以外的結點 重邊 父親結點和重結點連成的邊 輕...

樹鏈剖分 樹鏈剖分講解

好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...

演算法入門 樹鏈剖分 輕重鏈剖分

目錄 3.0 求 lca 4.0 利用資料結構維護資訊 5.0 例題 參考資料 資料結構入門 線段樹 發表於 2019 11 28 20 39 dfkuaid 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查詢 標記下傳 標記永久化 閱讀全文 樹鏈剖分用...