把一棵樹分成很多條鏈,然後利用資料結構(線段樹、樹狀陣列等)來維護這些鏈。
樹鏈剖分用於樹路徑資訊維護。
隨便剖分
隨機剖分
輕重鏈剖分(本文)
重結點:子樹結點數目最多的結點;
輕節點:父親節點中除了重結點以外的結點;
重邊:父親結點和重結點連成的邊;
輕邊:父親節點和輕節點連成的邊;
重鏈:由多條重邊連線而成的路徑;
輕鏈:由多條輕邊連線而成的路徑;
如圖:加粗的邊為重邊,紅點為每條重鏈的頂端節點(後稱top)。
性質1:輕邊(u,v),size(v)<=size(u)/2。
如果size(v)>size(u)/2
的話,那麼v是
u的size
值最大的兒子節點,則
(u,v)
為重邊。
性質2:從根到某一點的路徑上,不超過o(logn)條輕邊,不超過o(logn)條重路徑。
根到某一點的路徑上,輕邊最多的情況,就是所有的邊都是輕邊,那麼不可能超過
o(logn
)條的,乙個點到根節點的路徑上,是一條重路徑與一條輕邊交替出現,所以重路徑的條數最多和輕邊條數一樣,也就是不超過
o(logn)條。
重鏈剖分的過程為2
次dfs
需要用到的陣列:
siz[u]//用來儲存以u為根的子樹結點個數
top[u]//用來儲存當前結點u所在鏈的頂端節點
son[u]//用來儲存當前結點u的重兒子編號
dep[u]//用來儲存當前結點x的深度
fa[u]//用來儲存當前結點x的父親編號
id[u]//用來儲存樹中每個結點剖分後的新編號,即dfs序編號
rnk[pos]//用來儲存線段樹中位置為pos的結點在原樹上的編號
//tid和rnk互為反函式
第一次dfs:找重邊
inline void dfs1(int u,int fa,int d)
inline void q(int v,int u,int v1)
樹的統計count
純模板,沒什麼好說的,主要看個格式
**:
#include#include#include#includeusing namespace std;
#define n 1000005
int dep[n],siz[n],son[n],fat[n],id[n],top[n];
int tot,n,m,c[n];
struct node
t[n*4];
vectorg[n];
inline void dfs1(int u,int fa,int d)
inline void modify(int i,int x,int v)
int mid=(t[i].l+t[i].r)>>1;
if(x<=mid)
modify(i<<1,x,v);
else
modify(i<<1|1,x,v);
push_up(i);
}inline int q1(int l,int r,int i)
inline int q1(int v,int u)
inline int q2(int l,int r,int i)
inline int q2(int v,int u)
int main()
{ scanf("%d",&n);
for(int i=1;i
樹鏈剖分 樹鏈剖分講解
好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 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 摘要 線段樹的基本 建樹 區間查詢 單點修改 及高階操作 區間修改 單點查詢 區間修改 區間查詢 標記下傳 標記永久化 閱讀全文 樹鏈剖分用...
樹鏈剖分 樹剖換根
這是一道模板題。給定一棵 n 個節點的樹,初始時該樹的根為 1 號節點,每個節點有乙個給定的權值。下面依次進行 m 個操作,操作分為如下五種型別 換根 將乙個指定的節點設定為樹的新根。修改路徑權值 給定兩個節點,將這兩個節點間路徑上的所有節點權值 含這兩個節點 增加乙個給定的值。修改子樹權值 給定乙...