LCA的樹鏈剖分實現

2021-06-13 07:05:32 字數 1165 閱讀 6028

這篇本來是要在

樹鏈剖分小節

中寫的,但是我感覺這只是樹鏈剖分的乙個衍生物,所以另開了一篇,如果對樹鏈剖分部分還不是太了解,請看上面的鏈結。

計算樹中兩個節點的最近公共祖先,我們一般有爬山法,tarjan離線演算法,或者是將lca轉換成rmq來解,這裡講一講一種新的求lca的演算法,它是基於樹鏈剖分的。

我們先來複習一下樹鏈剖分中各個節點所維護的資訊:

1:siz[v]表示以v為根的子樹的節點總數。

2:dep[v]表示v的深度。

3:son[v]表示與v在同一重鏈上的v的兒子節點。

4:fa[v]表示v的父親節點。

5:top[v]表示v所在鏈的頂端節點。

(其實還有w[v],不過在這裡我們不需要)

我們先來看看樹鏈剖分求lca的**,然後再來看演算法的原理。

int lca(int a, int b)

}

是不是非常簡短呢。下面來分析這個演算法。

1:如果top[a]==top[b],說明a和b在同一條重鏈上,顯然它們中深度較小的點即為它們的最近公共祖先。

2:若果top[a]!=top[b],(說明a,b在不同的重鏈上)且a的深度較大,則此時a,b的lca不可能在a所在的重鏈上。

因為如果a,b的lca在a所在重鏈上,那麼top[a]顯然也為a,b的公共祖先,則若dep[up[a]]]>dep[b],則顯然不可能,若dep[up[a]]]<=dep[b],則設dep[up[a]]]為d,因為d>=dep[b],所以我沿著b向上搜尋,在深度d處也可以找到乙個點c為b的祖先,又因為a,b不在同一條重鏈上,所以top[a]!=c,這就意味著在同一深度,b有兩個不同的祖先,這是不可能的(因為是一棵樹),所以,lca不可能在a所在的重鏈上。所以我們可以將a上公升到up[a]的父節點,這時a,b的lca沒有變化。

3:若果top[a]!=top[b],且b的深度較大,同理我們可將b上公升到up[b]的父節點。

4: a,b不停地上公升,所以一定可以找到a,b的lca。

因為我們知道,在樹中任意一點到根的路徑上,重鏈數不會超過(logn),所以我們可以在o(logn)的時間複雜度內,將a,b的lca求出來。

因為我們求lca都是在重鏈上進行,所以結合線段樹,我們可以維護樹中任意兩點間路徑的資訊了,比如兩點間的最大邊最小邊,邊權和等等,這裡就不一一舉例了。

LCA 樹鏈剖分

剛打完lca板子,寫個東西記下 dfs第一遍求出 結點i的深度,以i為根的子樹大小,結點i的父親,並求出重鏈 dfs第二遍求出 結點i所在重鏈的鏈頂 如果在重鏈上 開始lca,兩個點往上找,深度大的點就往上跳,這個點如果在重鏈上,就跳到所在重鏈的鏈頂的父親處,在輕鏈上,就直接跳到自己父親上 洛谷lc...

樹鏈剖分求LCA

這裡先推薦兩道練習的裸題 首先是求點 codevs4605 lca 就是求兩個點的公共祖先,每次詢問xor上上乙個詢問的答案。先是兩遍dfs dfs1 把dep siz son求出來 dfs2 求出top和w siz v 表示以v為根的子樹的節點數 dep v 表示v的深度 根深度為1 top v ...

樹鏈剖分求lca

題目描述 給一棵有根樹,以及一些詢問,每次詢問樹上的2 個節點a b,求它們的最近公共祖先.輸入第一行乙個整數n.接下來n 個數,第i 個數fi 表示i 的父親是fi.若fi 0,則i 為樹根.接下來乙個整數m.接下來m 行,每行2 個整數a b,詢問節點 a xor lastans bxor la...