The lowest common ancestor problem is crucial to solving most tree problems. In a rooted tree, the lowest common ancestor of 2 nodes is the deepest node that is an ancestor of both nodes.

If the tree is rooted at node 1, then LCA(4, 6) = 2, LCA(5, 3) = 3, and LCA(6, 1) = 1.
There are many many different ways to find the lowest common ancestor of 2 nodes, however the most popular one is binary lifting.
The general idea for binary lifting is to precompute a 2D array par, where par[i][j] stores the 2^j th parent of i (0 <= j <= log2(N)). So par[i][0] stores the direct parent, par[i][1] stores the 2nd parent, etc.
We can precompute that array with a simple DFS as shown later.
Now suppose we receive a query (u, v) and we want to find the LCA of u and v. If u is an ancestor of v or vice versa, then we have already answered the query, so it suffices to first check if u or v is an ancestor of the other. If not, then we should find the highest ancestor of u (closest to root) that is not an ancestor of v. Suppose this node is k, then our LCA is par[k][0]. Clearly this is true since par[k][0] is an ancestor of both u and v and also the first one that is true.
To check if one node is an ancestor of another, we use the euler tour method.
| struct LCA{ //LCA with binary lifting vector<vector<int>> adj; vector<vector<int>> anc; int LG; int N; vector<int> in, out; //euler tour int timer = 0; LCA(int n){ LG = ceil(log2(n+1)); N = n; adj.resize(N+1); anc.resize(N+1); in.resize(N+1); out.resize(N+1); for(auto &u : anc)u.resize(ceil(log2(n+1)) + 2); } void ae(int u, int v){ adj[u].push_back(v); adj[v].push_back(u); } void process(int v = 1, int p = 0){ anc[v][0] = p; for(int i = 1; i <= LG; i++){ anc[v][i] = anc[anc[v][i-1]][i-1]; //binary lifting } in[v] = timer++; for(auto u : adj[v]){ if(u == p)continue; process(u, v); } out[v] = timer; } //kth ancestor //returns -1 is there is no kth parent int kth(int v, int k){ for(int i=0; i <= LG; i++){ if(k >> i & 1){ v = anc[v][i]; } } return (v == 0 ? – 1 : v); } bool isAnc(int u, int v){ return in[u] <= in[v] && out[u] >= out[v]; } int lca(int u, int v){ if(isAnc(u, v))return u; if(isAnc(v, u))return v; for(int i = LG; i >= 0; i–){ if(anc[u][i] != 0 && !isAnc(anc[u][i], v)){ u = anc[u][i]; } } return anc[u][0]; } } |