LCA之ST演算法(我只會這個)

2021-10-09 20:25:09 字數 1954 閱讀 3011

求有根樹的任意兩個節點的最近公共祖先。

解答這個問題之前,咱們得先搞清楚到底什麼是最近公共祖先。最近公共祖先簡稱lca(lowest common ancestor),所謂lca,是當給定乙個有根樹t時,對於任意兩個結點u、v,找到乙個離根最遠的結點x,使得x同時是u和v的祖先,x 便是u、v的最近公共祖先。

———摘自度娘

可能度娘裡面的話有些讀不懂(我的智商原因),在這裡我先舉個栗子

在本圖中,我們記點n,m的最近公共祖先為lca(n,m),則:

lca(5,6)= 1;因為5的父親為2,2的父親為1,6的父親為3,而3的父親為1;1為首個出現的祖先,故lca(5,6)= 1。

另一種理解方式是把t理解為乙個無向無環圖,而lca(t,u,v)即u到v的最短路上深度最小的點。

這裡給出乙個lca的例子:

對於t=

v=e=

則有:lca(t,5,2)=1

lca(t,3,4)=3

lca(t,4,5)=3

———摘自度娘

這個演算法主要實現方式是用dp

查詢階段需要用到倍增

我們定義dp[i][j]表示i節點向上爬2

j2^j

2j後所到達的節點;查詢時,假設要查詢的兩個點n,m的最近公共祖先,還是以下圖為例查詢lca(7,6)。

7的深度為4,6的深度為3,首先把7這個結點的深度變為3,即7向上爬一層,變為4,然後就一起往上爬,第一次爬到2和3,2和3繼續爬就變成1,所以lca(7,6) = 1;

在查詢的時候,用倍增演算法可以把時間減少到log級別,**:

int

lca(

int x,

int y)

}return dp[x][0];}

初始化就不用說了吧……

void

init()

用dfs遍歷整顆樹,求出每個結點的父節點與子節點(因為輸入時是無序的)。時間複雜為o(n)。**:

void

find_son

(int now)}}

void

find_father

(int now)

}

#include

#include

using

namespace std;

const

int maxn =

1e5+5;

vector<

int> a[maxn]

, v[maxn]

;int dp[maxn][32

];int de[maxn]

, fa[maxn]

;bool vis[maxn]

;int n, m;

intlca

(int x,

int y)

}return dp[x][0

];}void

find_son

(int now)}}

void

find_father

(int now)

}void

dfs(

int now,

int step)

void

init()

void

read()

}void

write()

}int

main()

**可能有點複雜,將就著看吧……

(附:不了解倍增優化可以看一些rmq的部落格)

RMQ問題之ST演算法

st演算法 st演算法是用於解決rmq問題 區間最值問題 的一種強有力的工具。o nlogn 預處理,o 1 查詢最值,利用的是倍增的思想。但 但是,使用st演算法的條件是沒有修改操作,emmm 演算法流程 最大值為例 預處理 用f i j 表示,從i位置開始的2 j 個數中的最大值,例如f i j...

RMQ之ST演算法模板

1 include2 include 3 include4 using namespace std 5const int n 1e6 111 6 int max n 21 min n 21 a n 7void st int a,int n 預處理,o nlogn 820 21 22 23int lo...

RMQ問題之ST演算法

rmq問題 求長度為n的數列中,求 i,j 直接的最值。st演算法 一種動態規劃的方法。一 預處理dp陣列 對於區間 i,i 2 j 1 的最值,只需要知道區間 i,i 2 j 1 1 和區間 i 2 j 1 i 2 j 1 的最值即可。由此可的遞推方程 dp i,i 2 j 1 max dp i,...