|
| 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) |
0 commit comments