[Algorithm] LCA

Lowest Common Ancestor

최소 공통 조상을 O(logn)에 찾기위한 알고리즘이다. O(logn)에 찾기 위해서 parent 배열을 만드는데 이 배열을 만드는데 O(nlogn)의 시간이 필요하다. 그 이후에 쿼리에서는 O(logn)에 동작한다.

implementaion

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#include <bits/stdc++.h>

using namespace std;
vector<vector<int>> adj;
vector<vector<int>> parent;
vector<int> level;

void dfs(int node) { //O(v + e) => O(n) this case (because it's tree)
for(auto near : adj[node]) {
if(level[near] == 0) {
parent[near][0] = node;
level[near] = level[node] + 1;
dfs(near);
}
}
}

void init() { //o(nlogn)
int n = adj.size();
int m = parent[0].size();

for(int p = 0; p < m; p++) {
for(int node = 1; node < n; node++) {
if(parent[node][p] != -1) {
parent[node][p + 1] = parent[parent[node][p]][p];
}
}
}
}

int lca(int u, int v) { //o(logn)
if(level[u] < level[v]) swap(u, v);
int diff = level[u] - level[v];
int ma = parent[0].size();

for(int j = 0; diff; j++) {
if(diff & 1) u = parent[u][j];
diff /= 2;
}

if(u != v) {
for(int j = ma - 1; j >= 0; j--) {
if(parent[u][j] != -1 and parent[u][j] != parent[v][j]) {
v = parent[v][j];
u = parent[u][j];
}
}
u = parent[u][0];
}
return u;
}

int main() {
vector<vector<int>> edges = {{1, 2},{2, 3},{5, 6},{4, 2},{7, 5},{1,5}};
int n = 7;
level = vector<int>(n + 1, 0);
adj = vector<vector<int>>(n + 1);
parent = vector<vector<int>>(n + 1,vector<int>(log2(n) + 1, -1));

for(auto e : edges) {
adj[e[0]].push_back(e[1]);
adj[e[1]].push_back(e[0]);
}

level[1] = 1;
dfs(1);
init();
cout<<lca(3, 5)<<endl;

return 0;
}
Author: Song Hayoung
Link: https://songhayoung.github.io/2022/03/04/Algorithm/lca/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.