各種求lca的辦法

2021-08-23 12:41:48 字數 2816 閱讀 6883

1.暴力求

2.倍增求

3.用rmq求

4.用tarjan離線求

5.用樹鏈剖分求

6.(剛看到有乙個轉成二進位制求的)有點懵逼

1.關於暴力

有的時候是很快的(深度比較小),有時可以人為構造(如按秩合併),大部分時間可以被卡過,所以不是個好方法,但暴力出奇蹟啊,簡單地說就是乙個乙個往上找。

**我有個比較優美的

x1:=x;

while(fa[x1]<>x1)do

begin

bz[x1]:=true;

x1:=fa[x1];

end;

y1:=y;

while(fa[y1]<>y1)do

begin

if(bz[y1])then

begin

break;

end;

y1:=fa[y1];

end;

lca:=y1;

2.關於倍增

其實挺簡單的,暴力是乙個乙個往上跳,倍增就是2^n個往上跳。

我們想象一下,如果兩個點在同一深度,那麼如果它們的第2^n個祖先是不一樣的,那麼是不是說明lca還在他們2^n之上,那麼我們就都跳到他們的第2^n個祖先上,然後再繼續找。

但是,如果它們的第2^n個祖先是相等的,並不一定說明這就是它們的lca,因為在它們的lca之上的祖先都是一樣的(畫個圖,理解一下)

只有當n=0,2^0=1,也就是只往上跳乙個,然後它們一樣的話,那才能說明這是lca。

只要預處理出倍增的陣列,然後跳就行了。

至於深度不同,那就把深度較大的點往上跳到深度相同為止。

下面是預處理倍增(注意每個點的父親要在建圖就記錄好)

for i:=1 to 19 do

begin

for j:=1

to n do

begin

if(deep[j]>1 shl i)then

begin

fa[j,i]:=fa[fa[j,i-1],i-1];

//它第2^i-1個祖先的2^i-1個祖先就是它的2^i個祖先

end;

end;

end;

下面是倍增的主程式

if(deep[x]>deep[wz])then

//深度不同

begin

up(x,19);//大的往上跳

end;

if(deep[x]then

begin

up1(wz,19);

end;

doubleup(x,wz,19);//一起跳

下面是倍增的過程

procedure

up(var x:longint;s:longint);

begin

while(deep[x]<>deep[wz])do

begin

while(fa[x,s]=0)do dec(s);//沒有這個祖先

while(deep[fa[x,s]]do dec(s);

ans:=ans+1

shl s;//記錄到lca的距離

x:=fa[x,s];

end;

end;

procedure

up1(var wz:longint;s:longint);

//跟上面一樣

begin

while(deep[wz]<>deep[x])do

begin

while(fa[wz,s]=0)do dec(s);

while(deep[fa[wz,s]]do

begin

dec(s);

end;

ans:=ans+1

shl s;

wz:=fa[wz,s];

end;

end;

procedure

doubleup

(var x,wz:longint;s:longint);

begin

while(x<>wz)do

begin

while(fa[x,s]=0)do dec(s);

while(fa[x,s]=fa[wz,s])and(s>0)do dec(s);//相等時一定要s=0才跳

ans:=ans+(1

shl s)*2;//兩個都跳,所以要*2

x:=fa[x,s];

wz:=fa[wz,s];

end;

end;

沒了,簡潔明瞭。

3.關於rmq

剛剛學會,對於一棵樹,遍歷出尤拉序,什麼是尤拉序呢,類似於dfs序,但是返回的時候也要記錄

例如

那麼尤拉序就是

1 2 4 2 5 2 1 3 1

就是dfs的順序嘛

然後記錄下每個點第一次出現的地方。

1第一次出現在1

2第一次出現在2

3第一次出現在8

4第一次出現在3

5第一次出現在5

然後對與某兩個的lca就是在它們第一次出現地方之間找乙個深度最小的,用rmq維護(線段樹慢)

例如,3 5的lca,就是5 2 1 3裡深度最小的1,

4 5 的lca就是4 2 5裡深度最小的2

別的我還不會,太弱了。。。

ST求LCA的模板

預處理的時間複雜度是 o nlog2n 查詢時間是 o 1 include include include using namespace std const int maxn 10010 int rmq 2 maxn rmq陣列,就是尤拉序列對應的深度序列 struct st for int j ...

倍增法求 LCA

預處理 通過dfs遍歷,記錄每個節點到根節點的距離dist u 深度d u 並求出樹上每個節點i的2 j祖先f i j 求最近公共祖先,根據兩個節點的的深度,如不同,向上調整深度大的節點,使得兩個節點在同一層上,如果正好是祖先結束,否則,將連個節點同時上移,查詢最近公共祖先。include incl...

倍增法求lca

f i j 表示從i這個節點出發,向上走2 j步到達的點 超過了最大深度就返回0 那麼顯然有 因為相當於是從i點先向上走2 j 1 步,再走2 j 1 步。等價於一共走2 j步。然後求lca就是 先把深度大的那個點往上跳,使兩個點的深度相同。對應的 for int i 18 i 0 i if dep...