Lowest Common Ancestor
Description:
Quick lowest-common-ancestor queries using sparse tables. The function lca(x,y) takes two node identifiers in a rooted tree and returns their lowest common ancestor (LCA for short). The function takes O(lg N) time where N is the number of nodes in the tree. A O(N lg N) pre-processing step is needed to build the sparse table.
API
void init( void ); // Initialize the module (assumes that the tree is built and the number of nodes is stored in variable nvoid lca(int x, int y) // Lowest common ancestor of x and y
Other uses
This data structure can also be used to quickly answer path-queries in a (weighted) rooted tree. Examples include:
- Find sum of weights on path from node x to node y.
- Find min/max edge weight on path from node x to node y.
- Find weight of path from node x to node y.
The data structure can support updates by adding a function to update the sparse table. An update can be implemented in time O(lg N) so both operations are fast.
Implementation
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1000010; /* Max nodes */
const int M = 30; /* Max LOG */
int LG;
int n;
vector<int> adj[N]; /* Adjacency list */
int p[N][M]; /* Sparse table */
int depth[N];
void init( void ) {
LG = 0;
while((1 << LG) < n)
LG += 1;
for(int i = 0; i < n; i++)
for(int j = 0; j < LG; j++)
p[i][j] = -1;
}
void dfs(int x, int par = -1, int d = 0) {
depth[x] = d;
p[x][0] = par;
for(int i = 1; i < LG; i++)
if(p[x][i - 1] + 1)
p[x][i] = p[p[x][i - 1]][i - 1];
for(auto y: adj[x])
if(y != par)
dfs(y, x, d + 1);
}
int lca(int x, int y) {
if(depth[x] > depth[y])
swap(x, y);
for(int i = LG - 1; i >= 0; i--)
if((p[y][i] + 1) && (depth[p[y][i]] >= depth[x]))
y = p[y][i];
if(x == y)
return x;
for(int i = LG - 1; i >= 0; i--)
if((p[x][i] + 1) && (p[x][i] != p[y][i]))
x = p[x][i], y = p[y][i];
return p[x][0];
}
/* Example */
int main( void ) {
cin >> n;
for(int i = 0; i < n; i++)
adj[i].clear();
for(int i = 0; i < n; i++) {
int len;
cin >> len;
while(len--) {
int x;
cin >> x;
adj[i].push_back(x);
adj[x].push_back(i);
}
}
/* Init and pre-process */
init();
dfs(0);
/* Answer queries */
int q;
cin >> q;
while(q--) {
int x, y;
cin >> x >> y;
cout << lca(x, y) << endl;
}
return 0;
}