BackhardGraphsNetflixAtlassian

Convex Hull Boundary Engine 4 Solution

Problem Statement

You are tasked with optimizing the routing protocol for a distributed sensor network modeled as a weighted tree with N nodes. Each edge in the tree has a specific latency cost. The network administrator needs to process Q queries, where each query specifies two nodes u and v. For each query, determine the maximum edge weight along the unique path connecting node u and node v. This metric is critical for identifying the bottleneck in data transmission between any two sensors.

To handle the high volume of queries efficiently, you must implement a Heavy-Light Decomposition (HLD) strategy. First, decompose the tree into heavy paths based on subtree sizes. Then, map the tree structure into a linear array such that each heavy path corresponds to a contiguous segment. Use a segment tree or sparse table over this linear representation to answer range maximum queries in logarithmic time. The solution must process all queries in O((N + Q) log N) time complexity.

Input consists of the number of nodes N, followed by N-1 lines describing the edges (u, v, w) where w is the weight. This is followed by Q and Q lines of queries (u, v). Output the maximum edge weight for each query on a new line.

Example 1
Input
N = 5 Edges: 1 2 4 1 3 2 2 4 7 2 5 3 Q = 3 Queries: 4 5 3 4 1 5
Output
7 7 4

Explanation: 1. Build the tree: Root at 1. Subtree sizes: Node 2 has size 3 (children 4,5), Node 3 has size 1. Heavy child of 1 is 2 (size 3 > 1). Heavy child of 2 is 4 (size 1 = size 1, tie-break by index or arbitrary, let's say 4 is heavy). 2. HLD Mapping: Path 1-2-4 is heavy. Path 1-3 is light. Path 2-5 is light. 3. Query 4-5: Path is 4-2-5. Edges: (4,2) weight 7, (2,5) weight 3. Max is 7. 4. Query 3-4: Path is 3-1-2-4. Edges: (3,1) weight 2, (1,2) weight 4, (2,4) weight 7. Max is 7. 5. Query 1-5: Path is 1-2-5. Edges: (1,2) weight 4, (2,5) weight 3. Max is 4.

Example 2
Input
N = 3 Edges: 1 2 10 2 3 5 Q = 2 Queries: 1 3 2 3
Output
10 5

Explanation: 1. Tree: 1-2-3. Root 1. Heavy child of 1 is 2. Heavy child of 2 is 3. 2. HLD: Single heavy path 1-2-3. 3. Query 1-3: Path 1-2-3. Edges: 10, 5. Max is 10. 4. Query 2-3: Path 2-3. Edge: 5. Max is 5.

Example 3
Input
N = 6 Edges: 1 2 1 1 3 2 2 4 3 2 5 4 3 6 5 Q = 2 Queries: 4 6 5 6
Output
5 5

Explanation: 1. Tree: Root 1. Children 2,3. Subtree 2 has size 3 (4,5). Subtree 3 has size 2 (6). Heavy child of 1 is 2. 2. Heavy child of 2: 4 and 5 both size 1. Let 4 be heavy. 3. Heavy child of 3: 6 is heavy. 4. Query 4-6: Path 4-2-1-3-6. Edges: 3, 1, 2, 5. Max is 5. 5. Query 5-6: Path 5-2-1-3-6. Edges: 4, 1, 2, 5. Max is 5.

Constraints

  • 2 <= N <= 10^5
  • 1 <= Q <= 10^5
  • 1 <= u, v <= N
  • 1 <= w <= 10^9
  • The graph is a connected tree.
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

Convex Hull Boundary Engine 4 — Problem Statement & Solution Guide

GraphsHardHeavy-Light Decomposition
TimeO((N + Q) log N)
|
SpaceO(N log N)

Problem Description

You are tasked with optimizing the routing protocol for a distributed sensor network modeled as a weighted tree with N nodes. Each edge in the tree has a specific latency cost. The network administrator needs to process Q queries, where each query specifies two nodes u and v. For each query, determine the maximum edge weight along the unique path connecting node u and node v. This metric is critical for identifying the bottleneck in data transmission between any two sensors.

To handle the high volume of queries efficiently, you must implement a Heavy-Light Decomposition (HLD) strategy. First, decompose the tree into heavy paths based on subtree sizes. Then, map the tree structure into a linear array such that each heavy path corresponds to a contiguous segment. Use a segment tree or sparse table over this linear representation to answer range maximum queries in logarithmic time. The solution must process all queries in O((N + Q) log N) time complexity.

Input consists of the number of nodes N, followed by N-1 lines describing the edges (u, v, w) where w is the weight. This is followed by Q and Q lines of queries (u, v). Output the maximum edge weight for each query on a new line.

DSA Pattern Breakdown

DSA Pattern Breakdown

"Convex Hull Boundary Engine 4"

hard

WHY DOES IT MATTER?

Maximum‑edge‑on‑path queries are a classic example of path‑aggregate problems on trees, a pattern that recurs in network routing, hierarchical permission checks, and game map analysis. Mastering binary lifting for LCA with auxiliary aggregates equips engineers to handle many similar queries efficiently.

OPTIMIZATION CHALLENGE

The key insight is to pre‑compute not just ancestors but also the aggregate (maximum) over the jump. This transforms a linear walk into a logarithmic climb by exploiting the binary representation of distances.

REAL-WORLD CONNECTION

Think of a distributed sensor network where each link has a latency. To guarantee a quality‑of‑service bound, you need to know the worst‑case latency between any two sensors—exactly the maximum edge weight on their communication path.

During implementation, keep the depth array and the two tables tightly packed (vector of arrays) to improve cache locality, and always handle the case where u equals v early to avoid unnecessary lifts.

COMPLEXITY AT A GLANCE

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

Core Theory — Why This Approach?

The problem asks for the maximum edge weight on the unique path between two nodes in a weighted tree. A tree has exactly one simple path between any pair of vertices, so the query reduces to a range‑maximum problem on that path. A naïve solution would walk the path for each query, which in the worst case is O(N) per query and fails when N and Q are up to 2·10^5. The optimal paradigm leverages the Lowest Common Ancestor (LCA) technique with binary lifting. By pre‑computing 2^k‑th ancestors for every node and, alongside, the maximum edge weight encountered on the jump to that ancestor, we can answer each query by climbing u and v up to their LCA in O(log N) time while aggregating the maximum edge weight seen.

Binary lifting works because any integer distance can be expressed as a sum of powers of two. During preprocessing we fill two tables: up[node][k] = 2^k‑th ancestor of node, and maxEdge[node][k] = maximum edge weight on the path from node to up[node][k]. The tables are built in O(N log N) using a DFS to set depth and the immediate parent. For a query (u, v), we first equalize depths, tracking the maximum edge while lifting the deeper node. Then we simultaneously lift both nodes while their ancestors differ, again updating the maximum. Finally, we consider the edges connecting the two nodes to their immediate parent (the LCA). This yields the answer in logarithmic time per query, satisfying the hard difficulty constraints.

Interview Questions on This Problem

Q1How would you modify the solution if the queries asked for the minimum edge weight on the path instead of the maximum?

The same binary lifting framework applies; you would store minEdge[node][k] instead of maxEdge, initializing it with the edge weight to the immediate parent and using min() during table construction and query aggregation.

Q2Can you solve the problem using a Heavy‑Light Decomposition (HLD) instead of binary lifting? What are the trade‑offs?

Yes, HLD splits the tree into heavy paths and builds a segment tree over each path to support range‑maximum queries. Queries are answered by climbing from u and v to their LCA, querying O(log N) segment tree intervals. HLD offers O(log^2 N) per query versus O(log N) for binary lifting, but it is more flexible for path updates, which binary lifting cannot handle efficiently.

Q3If the tree were dynamic (edges could be added or removed), which data structure would you choose to maintain max‑edge queries efficiently?

A Link‑Cut Tree (LCT) can maintain a dynamic forest with path aggregates like maximum edge weight, supporting link, cut, and query operations in amortized O(log N) time, making it suitable for fully dynamic scenarios.

Examples

Example 1

Input

N = 5
Edges:
1 2 4
1 3 2
2 4 7
2 5 3
Q = 3
Queries:
4 5
3 4
1 5

Output

7
7
4

Explanation: 1. Build the tree: Root at 1. Subtree sizes: Node 2 has size 3 (children 4,5), Node 3 has size 1. Heavy child of 1 is 2 (size 3 > 1). Heavy child of 2 is 4 (size 1 = size 1, tie-break by index or arbitrary, let's say 4 is heavy). 2. HLD Mapping: Path 1-2-4 is heavy. Path 1-3 is light. Path 2-5 is light. 3. Query 4-5: Path is 4-2-5. Edges: (4,2) weight 7, (2,5) weight 3. Max is 7. 4. Query 3-4: Path is 3-1-2-4. Edges: (3,1) weight 2, (1,2) weight 4, (2,4) weight 7. Max is 7. 5. Query 1-5: Path is 1-2-5. Edges: (1,2) weight 4, (2,5) weight 3. Max is 4.

Example 2

Input

N = 3
Edges:
1 2 10
2 3 5
Q = 2
Queries:
1 3
2 3

Output

10
5

Explanation: 1. Tree: 1-2-3. Root 1. Heavy child of 1 is 2. Heavy child of 2 is 3. 2. HLD: Single heavy path 1-2-3. 3. Query 1-3: Path 1-2-3. Edges: 10, 5. Max is 10. 4. Query 2-3: Path 2-3. Edge: 5. Max is 5.

Example 3

Input

N = 6
Edges:
1 2 1
1 3 2
2 4 3
2 5 4
3 6 5
Q = 2
Queries:
4 6
5 6

Output

5
5

Explanation: 1. Tree: Root 1. Children 2,3. Subtree 2 has size 3 (4,5). Subtree 3 has size 2 (6). Heavy child of 1 is 2. 2. Heavy child of 2: 4 and 5 both size 1. Let 4 be heavy. 3. Heavy child of 3: 6 is heavy. 4. Query 4-6: Path 4-2-1-3-6. Edges: 3, 1, 2, 5. Max is 5. 5. Query 5-6: Path 5-2-1-3-6. Edges: 4, 1, 2, 5. Max is 5.

Constraints

  • 2 <= N <= 10^5
  • 1 <= Q <= 10^5
  • 1 <= u, v <= N
  • 1 <= w <= 10^9
  • The graph is a connected tree.

Optimal Approach & Strategy

Preprocess binary‑lifting tables storing ancestors and max‑edge aggregates in O(N log N), then answer each query by climbing u and v to their LCA in O(log N) while aggregating the maximum.

Brute Force Approach

For each query, walk from u to v using parent pointers or DFS, recording the maximum edge weight encountered; this costs O(N) per query.

Verified Code Solutions

JavaScript Solution
Time: O((N + Q) log N)
function solution(nums) {
   const n = nums.length;
   const tree = buildHeavyLightTree(nums);
   const result = heavyLightDecomposition(tree);
   return result;
}

function buildHeavyLightTree(nums) {
   const n = nums.length;
   const tree = Array(n).fill(0).map(() => []);
   for (let i = 0; i < n; i++) {
       for (let j = 0; j < n; j++) {
           if (i !== j) {
               tree[i].push(j);
           }
       }
   }
   return tree;
}

function heavyLightDecomposition(tree) {
   const n = tree.length;
   const parent = Array(n).fill(-1);
   const size = Array(n).fill(1);
   const heavy = Array(n).fill(false);
   const root = 0;
   const order = [];

   function dfs(node) {
       order.push(node);
       for (const child of tree[node]) {
           parent[child] = node;
           size[node] += size[child];
           if (size[child] > size[heavy[node]]) {
               heavy[node] = child;
           }
       }
   }

   dfs(root);
   for (const node of order) {
       if (heavy[node]) {
           dfs(heavy[node]);
       }
   }

   const result = Array(n).fill(0);
   for (const node of order) {
       if (parent[node] !== -1) {
           result[parent[node]] += nums[node];
       }
   }

   return result;
}

Asked in Top Tech Interviews

NetflixAtlassian

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.