最近公共祖先(LCA) 學習筆記

2021-10-03 22:31:42 字數 1774 閱讀 4524

顧名思義,就是兩個結點的最近公共父結點;

這裡運用了倍增的思路,當你想要乙個個的往上遞增時,複雜度很高,可以把要遞增的數量換成二進位制表示(因為任意乙個數都可以由二進位制數相加得到);

比如11,可以由 2^3=8,2 ^1=2, 2 ^0=1,相加而成;所以11這個數可以先加8,在加2,在加1得到;

這裡有兩個預處理,乙個是得到每個結點所在的層數,乙個是得到每個結點往上走2的 j 次方次得到的結點;

這兩個操作可以放在乙個dfs函式裡面,應該非常好理解:

fa[sn][i]=fa[fa[sn][i-1]][i-1];可以手動模擬,大致意思為2^n=2 ^n-1 *+2 ^ n-1;

void

dfs(

int sn,

int ft)

}

這裡還學到一種預處理log_2(i)+1的方法:

for

(int i=

1;i<=n;i++

) lg[i]

=lg[i-1]

+(1<==i)

;//預處理(log_2(i))+1的值

這個東西就是求乙個數要用二進位制數組成的最大次數:

比如11,它的lg[11]=4,我們在呼叫lg[11]的時候還要減去1,也就是說要組成11,最多只要3次;

然後核心的 lca **主要的思路就是:先使 x 和 y 在同一層,然後在一起往上走,找到最頂部的兩個結點 x 和 y ,結點 x 和 y 的父節點相等,那麼 x 的父節點就是答案;

int

lca(

int x,

int y)

}return fa[x][0

];}

全部題目來做這道題:

【模板】最近公共祖先(lca)

全部**:

#include

#define ll long long

#define pa pair

#define ls k<<1

#define rs k<<1|1

#define inf 0x3f3f3f3f

using

namespace std;

const

int n=

500100

;const

int m=

1000100

;const ll mod=

100000000

;int n,m,s,head[n]

,cnt,lg[n]

,dep[n]

,fa[n][40

];struct nodeedge[m]

;void

add(

int p,

int q)

void

dfs(

int sn,

int ft)

}int

lca(

int x,

int y)

}return fa[x][0

];}int

main()

for(

int i=

1;i<=n;i++

) lg[i]

=lg[i-1]

+(1<==i)

;//預處理(log_2(i))+1的值

dfs(s,0)

;while

(m--

)return0;

}

LCA 最近公共祖先 學習筆記

lca指最近公共祖先。他有許多的求法和應用。首先最簡單的 跳到同一深度後,再一起向上跳,跳到同一節點為止。這個方法時間複雜度最壞為 o n 如果不是乙個老善人是不會讓你過的。如何優化這個方法呢?我們可以試試倍增,每次上跳多個節點,這樣時間複雜度就只有 log n 了。上p3379 可以結合 食用 i...

最近公共祖先 LCA 最近公共祖先

直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...

最近公共祖先 最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...