Binary Lifting, O(NlogN) preprocessing, O(logN) for each query
Sparse Table, O(NlogN) preprocessing, O(1) for each query
Hmm, these are the Competitive Programming approaches. But for regular LeetCode, one of the ways you can approach this is doing it recursively.
1. Binary Lifting
Erritcho gave a tutorial about this technique, as well as Algorithms Live. Think about it like a Binary Search on trees.
Binary lifting requires O(NlogN) for preprocessing the tree, and then O(logN) for each LCA query.
up[i][j] is the 2^j-th ancestor above the node i
tin = time in (of first visit)
tout = time out (time we left)
Since we do DFS, we can use this information to determine in constant time if a node is an ancestor of another node. Does this have to do with the Euler Tour?
2. Sparse Table
This idea is first built on the Euler Tour technique. We reduce the LCA problem down to a RMQ problem, which is then solved using a sparse table.
The code below implements LCA for a Segment Tree. It seems a bit more complicated…