Skip to content

Commit 27a1f10

Browse files
authored
Merge pull request #40 from souvikmahato-sm/new_changes
Added algorithm to calculate LCA by @souvikmahato-sm
2 parents 4c6690d + e0ae820 commit 27a1f10

File tree

3 files changed

+132
-2
lines changed

3 files changed

+132
-2
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Lowest Common Ancestor
2+
3+
Given a rooted tree \\(T\\) of \\(n\\) nodes. The ancestors of a \\(node\ u\\) are all the nodes in the path from \\(node\ u\\) to \\(root\\) (excluding \\(u\\)).
4+
Now Let's see how we can find \\(LCA\\) of two \\(node\ u\\) and \\(v\\).
5+
<br><div align = "center">
6+
<img height = "175" src = "https://user-images.githubusercontent.com/58760297/105862267-9aa4bf80-6015-11eb-86b1-3b8f03040904.png"/>
7+
</div><br>
8+
9+
## Algorithm \\(1\\) : \\(O(n)\\)
10+
11+
climb up from the deeper \\(node\\) such that \\(depth[u] == depth[v]\\). <br>
12+
Now climb up from both the node until \\(u == v\\).
13+
14+
<br><div align = "center">
15+
<img height = "400" src = "https://user-images.githubusercontent.com/58760297/105890276-2c6ff500-6035-11eb-9c71-56e89742f652.png"/>
16+
</div><br>
17+
18+
### Implementation :
19+
20+
```cpp
21+
int LCA(int u, int v){
22+
if(depth[u] > depth[v])
23+
swap(u, v);
24+
int h = depth[v] - depth[u];
25+
for(int i = 0; i < h; i++) // lifting v up to the same level as u
26+
v = parent[v];
27+
28+
while(u != v){ // climbing up egde by egde from u and v
29+
u = parent[u];
30+
v = parent[v];
31+
}
32+
return u;
33+
}
34+
```
35+
36+
Here, as we are climbing edge by egde, hence in worst case it will take \\(O(n)\\) time to compute LCA.
37+
38+
## Algorithm \\(2\\) : \\(O(logn)\\)
39+
40+
Instead of climbing edge by edge, we can make higher jumps from the node : say, from \\(node\ u\\) to \\(2^i\\) distant ancestor of \\(u\\). We need to precompute \\(ancestor[n][k]\\) : such that, \\(ancestor[i][j]\\) will store \\(2^j\\) distant ancestor of \\(node\ i\\).
41+
42+
\\(n\\) = no. of nodes
43+
if \\(2^k > n\\), then we jump off the tree. Hence \\( k = 1 + log_2(n) \\)
44+
45+
46+
We know, \\(2^j = 2^{j-1} + 2^{j-1}\\)
47+
therefore, \\(ancestor[i][j] = ancestor[\ ancestor[i][j-1]\ ][j-1]\\)
48+
Note : \\(parent[root] = -1\\); \\(ancestor[i][0]\\) is simply the parent of \\(node\ i\\).
49+
```cpp
50+
// Computing ancestor table
51+
int k = 1 + log2(n);
52+
vector<vector<int>> ancestor(n+1, vector<int> (k));
53+
54+
for(int i = 1; i <= n; i++){
55+
ancestor[i][0] = parent[i];
56+
}
57+
58+
for(int i = 1; i <= n; i++){
59+
for(int j = 1; j < k; j++){
60+
if(ancestor[i][j-1] != -1) // we didn't jump off the tree
61+
ancestor[i][j] = ancestor[ ancestor[i][j-1] ][j-1]
62+
else
63+
ancestor[i][j] = -1
64+
}
65+
}
66+
```
67+
### Binary Lifting :
68+
Now say, we need to make a jump of height \\(h = 45\\) from a \\(node\ u\\).
69+
\\(h = 45 = (101101)_2 = (2^5 + 2^3 + 2^2 + 2^0) jumps\\). <br>
70+
we can implement this jump as following :
71+
```cpp
72+
int jump(int u, int h){
73+
for(int i = 0; h && u != -1;i++){
74+
if(h & 1)
75+
u = ancestor[u][i];
76+
h = h >> 1;
77+
}
78+
return u;
79+
}
80+
```
81+
### Computing LCA :
82+
83+
Using the \\(Binary\ Lifting\\) technique, make jump of a \\(height = depth[v] - depth[u]\\) from the deeper \\(node\ v\\).
84+
85+
if \\(u == v\\) already then \\(return\ u\\).
86+
87+
from \\(node\ u\\) and \\(node\ v\\), make jump as high as possible such that \\(ancestor[u][jump]\ != ancestor[v][jump]\\),
88+
then eventually we will reach a node, \\(parent[u] = parent[v] = LCA(u, v)\\)
89+
90+
thus \\(return\ parent[u]\\).
91+
92+
93+
<div align = "center">
94+
<img height = "400" src = "https://user-images.githubusercontent.com/58760297/105969917-caec6c80-60ae-11eb-8405-4d1f2e83a525.png"/>
95+
</div>
96+
97+
### Implementation :
98+
99+
```cpp
100+
int LCA(int u, int v){
101+
if(depth[u] > depth[v])
102+
swap(u, v);
103+
v = jump(v, depth[v] - depth[u]);
104+
if(u == v)
105+
return u;
106+
107+
int h = 1 + log2(depth[u]);
108+
for(int i = h-1; i >= 0; i--){
109+
if(ancestor[u][i] != -1 && ancestor[u][i] != ancestor[v][i]){
110+
u = ancestor[u][i];
111+
v = ancestor[v][i];
112+
}
113+
}
114+
return parent[u];
115+
}
116+
```
117+
## Problems
118+
- [Company Querries I](https://cses.fi/problemset/task/1687)
119+
- [Company Querries II](https://cses.fi/problemset/task/1688)
120+
121+
## Reference
122+
- [Algorithms Live](https://youtu.be/kOfa6t8WnbI)
123+
- [cp-algorithms](https://cp-algorithms.com/graph/lca_binary_lifting.html)

src/Graph/Tree/Tree.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1-
## **Tree**
1+
# Tree
22

33
We can define *Tree* as a connected undirected graph with *no cycles* .
44

55
There are some more ways we can define Tree . Here are some equivalent definitions :
66

77
- connected undirected graph with N nodes and N-1 edges.
88
- connected undirected graph with only unique paths i.e there is one and only path from one node to another.
9-
- connected undirected graph where if you remove 1 edge it no longer remains connected.
9+
- connected undirected graph where if you remove 1 edge it no longer remains connected.
10+
11+
<br>
12+
13+
## Tree Algorithms :
14+
- [Diameter](./Diameter/diameter.md)
15+
- [Lowest Common Ancestor](./Lowest_Common_Ancestor/LCA.md)

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
- [Graph](./Graph/Graph.md)
3232
- [Tree](./Graph/Tree/Tree.md)
3333
- [Diameter](./Graph/Tree/Diameter/diameter.md)
34+
- [Lowest Common Ancestor](./Graph/Tree/Lowest_Common_Ancestor/LCA.md)
3435
- [String Processing](./String_Processing/String_Processing.md)
3536
- [String Hashing](./String_Processing/String_Hashing/String_Hashing.md)
3637
- [Rabin-Karp Algorithm](./String_Processing/Rabin-Karp_Algorithm/Rabin-Karp.md)

0 commit comments

Comments
 (0)