BackmediumTreesAmazonCred

Optimal Grid Path Protocol 6 Solution

Problem Statement

You are given a rooted binary tree with N nodes, where each node is indexed from 1 to N. The root of the tree is node 1. You are also given an array of Q queries. Each query consists of two integers, u and v, representing two nodes in the tree. For each query, determine the Lowest Common Ancestor (LCA) of nodes u and v. The LCA is defined as the deepest node that is an ancestor of both u and v. Note that a node is considered an ancestor of itself.

To efficiently handle multiple queries on a static tree, you may employ the Binary Lifting technique. Preprocess the tree to store the 2^k-th ancestor of every node. This allows you to jump up the tree in logarithmic time for each query. The preprocessing step involves computing the depth of each node and building a table of ancestors up to the maximum power of two required by the tree's height.

Your task is to implement a function that takes the tree structure and the list of queries as input, and returns an array containing the LCA node index for each query in the same order as the input queries.

Example 1
Input
Tree: 1->2, 1->3, 2->4, 2->5, 3->6, 3->7 Queries: [[4, 5], [4, 6], [7, 5], [1, 1]]
Output
[2, 1, 1, 1]

Explanation: Query 1: LCA of 4 and 5. Both are children of 2. LCA is 2. Query 2: LCA of 4 and 6. Path 4->2->1 and 6->3->1. Common ancestors are 1. LCA is 1. Query 3: LCA of 7 and 5. Path 7->3->1 and 5->2->1. Common ancestors are 1. LCA is 1. Query 4: LCA of 1 and 1. A node is its own ancestor. LCA is 1.

Example 2
Input
Tree: 1->2, 2->3, 3->4, 4->5 Queries: [[5, 3], [2, 5], [4, 4]]
Output
[3, 2, 4]

Explanation: Query 1: LCA of 5 and 3. Path 5->4->3. 3 is an ancestor of 5. LCA is 3. Query 2: LCA of 2 and 5. Path 2->3->4->5. 2 is an ancestor of 5. LCA is 2. Query 3: LCA of 4 and 4. LCA is 4.

Example 3
Input
Tree: 1->2, 1->3, 2->4, 3->5, 4->6, 5->7 Queries: [[6, 7], [6, 4], [7, 5]]
Output
[1, 4, 5]

Explanation: Query 1: LCA of 6 and 7. Path 6->4->2->1 and 7->5->3->1. Common ancestor is 1. LCA is 1. Query 2: LCA of 6 and 4. Path 6->4. 4 is an ancestor of 6. LCA is 4. Query 3: LCA of 7 and 5. Path 7->5. 5 is an ancestor of 7. LCA is 5.

Constraints

  • 1 <= N <= 10^5
  • 1 <= Q <= 10^5
  • 1 <= u, v <= N
  • The tree is connected and rooted at node 1
  • The depth of the tree is at most 10^5
Live Compiler1 Free Run Available
Loading Editor...
Test Cases & Output
Click "Run" to test your 1 free compile trial!

🚀 Practice this problem

Run code, get AI hints & track streak

Sign Up Free

Optimal Grid Path Protocol 6 — Problem Statement & Solution Guide

TreesMediumBinary Lifting LCA
TimeO((N + Q) log N)
|
SpaceO(N log N)

Problem Description

You are given a rooted binary tree with N nodes, where each node is indexed from 1 to N. The root of the tree is node 1. You are also given an array of Q queries. Each query consists of two integers, u and v, representing two nodes in the tree. For each query, determine the Lowest Common Ancestor (LCA) of nodes u and v. The LCA is defined as the deepest node that is an ancestor of both u and v. Note that a node is considered an ancestor of itself.

To efficiently handle multiple queries on a static tree, you may employ the Binary Lifting technique. Preprocess the tree to store the 2^k-th ancestor of every node. This allows you to jump up the tree in logarithmic time for each query. The preprocessing step involves computing the depth of each node and building a table of ancestors up to the maximum power of two required by the tree's height.

Your task is to implement a function that takes the tree structure and the list of queries as input, and returns an array containing the LCA node index for each query in the same order as the input queries.

DSA Pattern Breakdown

DSA Pattern Breakdown

"Optimal Grid Path Protocol 6"

medium

WHY DOES IT MATTER?

LCA is a core pattern for tree queries, enabling efficient computation of distances, path sums, and other properties. It is essential for problems involving hierarchical data, such as file systems, organizational charts, and version control systems.

OPTIMIZATION CHALLENGE

The key insight is to preprocess the tree to store ancestors at powers of two, allowing logarithmic-time queries. This reduces the per-query time from O(N) to O(log N), making it feasible for large inputs.

REAL-WORLD CONNECTION

In distributed systems, LCA can be used to find the common ancestor of two nodes in a network topology, which is useful for routing and fault tolerance. In version control systems like Git, LCA helps determine the common commit from which two branches diverged.

In interviews, clearly explain the preprocessing step and how the lifting works. Emphasize the trade-off between preprocessing time and query time, and be prepared to discuss edge cases like when one node is an ancestor of the other.

COMPLEXITY AT A GLANCE

⏱ Time:O((N + Q) log N)
💾 Space:O(N log N)

Core Theory — Why This Approach?

The Lowest Common Ancestor (LCA) problem in a rooted tree is a fundamental query that asks for the deepest node that is an ancestor of two given nodes. A naive approach involves traversing from the root to each node, storing their paths, and finding the last common node in these paths. While this works for small trees, it requires O(N) time per query, leading to O(N*Q) total complexity, which is infeasible for large N and Q (e.g., N, Q up to 10^5). The optimal paradigm relies on preprocessing the tree to answer each query in O(1) or O(log N) time.

Interview Questions on This Problem

Q1How would you handle LCA queries if the tree is dynamic, with nodes being added or removed?

For dynamic trees, static preprocessing like Binary Lifting is insufficient. One might use Euler Tour + RMQ with a dynamic segment tree or use Link-Cut Trees, which support path queries and updates in O(log N) time. However, for most standard interviews, the tree is static, so Binary Lifting is the expected solution.

Q2What is the time complexity of answering an LCA query using Binary Lifting after preprocessing?

The preprocessing takes O(N log N) time and space. Each query can be answered in O(log N) time by lifting the deeper node to the same depth as the other, and then lifting both nodes simultaneously until their parents are the same.

Q3Can you explain how Binary Lifting works for LCA?

Binary Lifting precomputes the 2^k-th ancestor of every node. To find the LCA of u and v, first lift the deeper node to the same depth as the other. Then, lift both nodes up by powers of two from largest to smallest, ensuring they don't jump past the LCA. Finally, the parent of the nodes is the LCA.

Examples

Example 1

Input

Tree: 1->2, 1->3, 2->4, 2->5, 3->6, 3->7
Queries: [[4, 5], [4, 6], [7, 5], [1, 1]]

Output

[2, 1, 1, 1]

Explanation: Query 1: LCA of 4 and 5. Both are children of 2. LCA is 2. Query 2: LCA of 4 and 6. Path 4->2->1 and 6->3->1. Common ancestors are 1. LCA is 1. Query 3: LCA of 7 and 5. Path 7->3->1 and 5->2->1. Common ancestors are 1. LCA is 1. Query 4: LCA of 1 and 1. A node is its own ancestor. LCA is 1.

Example 2

Input

Tree: 1->2, 2->3, 3->4, 4->5
Queries: [[5, 3], [2, 5], [4, 4]]

Output

[3, 2, 4]

Explanation: Query 1: LCA of 5 and 3. Path 5->4->3. 3 is an ancestor of 5. LCA is 3. Query 2: LCA of 2 and 5. Path 2->3->4->5. 2 is an ancestor of 5. LCA is 2. Query 3: LCA of 4 and 4. LCA is 4.

Example 3

Input

Tree: 1->2, 1->3, 2->4, 3->5, 4->6, 5->7
Queries: [[6, 7], [6, 4], [7, 5]]

Output

[1, 4, 5]

Explanation: Query 1: LCA of 6 and 7. Path 6->4->2->1 and 7->5->3->1. Common ancestor is 1. LCA is 1. Query 2: LCA of 6 and 4. Path 6->4. 4 is an ancestor of 6. LCA is 4. Query 3: LCA of 7 and 5. Path 7->5. 5 is an ancestor of 7. LCA is 5.

Constraints

  • 1 <= N <= 10^5
  • 1 <= Q <= 10^5
  • 1 <= u, v <= N
  • The tree is connected and rooted at node 1
  • The depth of the tree is at most 10^5

Optimal Approach & Strategy

Preprocess the tree using Binary Lifting to store ancestors at powers of two. For each query, lift the deeper node to the same depth, then lift both nodes simultaneously until their parents are the same. This takes O(log N) time per query.

Brute Force Approach

For each query, traverse from the root to both nodes, storing their paths. Find the last common node in these paths. This takes O(N) time per query.

Verified Code Solutions

JavaScript Solution
Time: O((N + Q) log N)
function solution(nums) {
   let sum = 0;
   for (let num of nums) {
       sum += num;
   }
   return sum;
}

Asked in Top Tech Interviews

AmazonCred

Solve in Interative Editor

Ready to test your code? Open our built-in compiler, run custom test suites, and see detailed complexity analysis reports instantly.