樹鏈剖分定義只是把一棵樹拆成鏈來處理而已,即將樹上的某些段一起通過資料結構優化進行處理來降低複雜度。
樹鏈剖分相關定義重兒子:ve
[v] 為
u 的子節點中ve
值最大的,那麼
v 就是
u的重兒子(將子樹中最長的那一條鏈一起處理來降低複雜度)。
輕兒子:
u 除了重兒子的其它子節點。
重邊:點
u與其重兒子的連邊。
輕邊:點
u 與其輕兒子的連邊。
重鏈:由重邊連成的路徑。
輕鏈:輕邊。
樹鏈剖分基本性質如果(v
,u)為輕邊,則ve
[u]×2[v
] ;
從根到某一點的路徑上輕鏈、重鏈的個數都不大於logn。
樹鏈剖分獨特之處主要針對路徑進行處理,我們平時處理一顆樹的路徑的方案一般就是求解lc
a o(
nlog
n)構建,o(
logn
) 進行查詢,比如一般的求解路徑上的最大邊權,點權之類的一般lca倍增法都可以解決,如果再離線一下,或許複雜度更低。
但是樹鏈剖分的獨特之處就是可以對路徑進行修改,一般結合線段樹進行處理,查詢更新的複雜度就是o(
logn
)
樹鏈剖分理解拿求解一條路徑上的最大值做例子,樹鏈剖分的思想就是,先對路徑進行預處理,將路徑上的資料分為幾段,然後再對這幾段求最大值,有點像分桶法。
看下圖:
比如我們要求解從頂點
11 到頂點
14 路徑上邊權的最大值,我們可以求出1−
4−9−
13−14 這條路徑上的最大值s1
,然後求出1−
2 路徑上的最大值s2
,然後再求出2−
6−11 路徑上的最大值s3
。然後我們再求解ma
x(s1
,s2,
s3) 的值就可以得到結果
[ 黑色的路徑表示圖中黑色的路徑,代表著重兒子,藍色的則是代表著不是重兒子的路徑]
從圖上我們可以看出,重兒子所在的路徑是子樹中路徑最長的,這也是為什麼重兒子的定義是子樹中節點最多的子節點,然後我們也發現黑色的路徑上的藍色編號是連續的,這是為了將這個長的路徑儲存在一段連續的區間,那麼我就可以了對這塊連續區間進行操作了。
也許大家已經想到了這樣規定的好處,因為越長的,我就一起處理,效率自然是越高了,重兒子就是這麼規定而來的。
然後我們對於區間求最值有很多方法,線段樹一般就是最優的。
相關陣列定義de
ep[u
]:來儲存當前節點
u 的深度fa
[u]:
用來儲存當前節點
u 的父親ve
[u]:
用來儲存以
u 為根的子樹節點個數so
n[u]
:用來儲存當前節點
u 的重兒子to
p[u]
:用來儲存當前節點
u 的所在鏈的頂端節點p[
u]:用來儲存當前節點u
fp:用來儲存線段樹相應位置儲存的是當前哪個節點
模板**dfs1
void dfs1(int u, int pre, int d) }}
第乙個df
s1是為了找重邊,記錄下所有的重邊以及相關關係
模板**dfs2
void dfs2(int u, int sp)
}
第二個dfs2就是為了連線重邊形成重鏈,即將這條長路徑給連線起來,具體步驟:以根節點為起點,沿著重邊向下拓展,拉成重鏈,不在當前重鏈上的節點,都以該節點為起點向下重新拉一條重鏈。
到此,樹鏈剖分部分完畢,構造的每條重鏈相當於一段連續的區間,然後就是用資料結構處理資料
[ 一般是線段樹處理]。
如何沿著路徑進行處理(以查詢最大值為例)步驟跟在求解
11 到
14 的最大值一樣。
int find(int u, int v)
tmp = max(tmp, query(1, p[f1], p[u]));
u = fa[f1];
f1 = top[u];
}if(u == v)return tmp;
if(deep[u] > deep[v]) swap(u, v);
return
max(tmp, query(1, p[son[u]], p[v]));
}
分析:
如果u與v在同一條重鏈上,那麼就直接修改了,因為他們是連續的
如果不在一條重鏈上,則往一條重鏈上靠攏,然後就會程式設計一條重鏈 [
有些地方不一定說得很清楚,希望大家指出,謝謝!]
詳解樹鏈剖分
樹鏈剖分,顧名思義為將鏈剖開分成多條。當我們想要修改樹上一條路的值或求值時,我們暴力只能用乙個個修改,這是非常慢的。這時,我們就要想乙個辦法,資料結構?但是資料結構我們都需要連續修改,可是樹上路徑的編號是不連續的。於是我們想了乙個辦法。我們先定義 fa x 為x的父親 dep x 為x的深度 siz...
樹鏈剖分詳解
重兒子 對於每乙個非葉子節點,它的兒子中 以那個兒子為根的子樹節點數最大的兒子 為該節點的重兒子 ps 感謝 shzr大佬指出我此句話的表達不嚴謹qwq,已修改 輕兒子 對於每乙個非葉子節點,它的兒子中 非重兒子 的剩下所有兒子即為輕兒子 葉子節點沒有重兒子也沒有輕兒子 因為它沒有兒子。重邊 乙個父...
樹鏈剖分詳解
樹鏈剖分,說白了就是一種讓你 不得不強行增加1k的資料結構 dms 個人理解 1 joy 證明出題人非常毒瘤 可以非常友 bao 好 li 的解決一些樹上問題 grimacing 樹鏈剖分的思想比較神奇 它的思想是 把一棵樹拆成若干個不相交的鏈,然後用一些資料結構去維護這些鏈 那麼問題來了 首先明確...