BackhardGraphsUberMicrosoft

Convex Hull Boundary Engine Solution

Problem Statement

Convex Hull Boundary Engine

You are given a rooted tree with N vertices numbered from 1 to N (vertex 1 is the root). Each vertex i is associated with a linear function f_i(x) = m_i·x + b_i, where m_i and b_i are integers. After the tree is built, you must answer Q independent queries.

Each query provides a vertex v and an integer x. Consider all vertices that lie on the unique simple path from the root (1) to v, inclusive. Among the functions attached to those vertices, evaluate each at the given x and output the maximum value.

Formally, for a query (v, x) compute:

answer = max_{u on path(1, v)} ( m_u * x + b_u )

All answers fit in 64‑bit signed integers. Design an algorithm that processes the whole input within the limits.

Input format

N u1 v1 u2 v2 ... (N‑1 lines describing edges) m1 b1 m2 b2 ... (N lines of slopes and intercepts) Q v1 x1 v2 x2 ... (Q lines of queries)

Output format For each query, output a single line containing the computed maximum.

The intended solution combines Heavy‑Light Decomposition to break root‑to‑node paths into O(log N) segments and a Li Chao segment tree (or any convex‑hull trick structure) on each heavy chain to answer maximum‑line queries in logarithmic time.

Example 1
Input
5 1 2 1 3 2 4 2 5 2 3 -1 5 0 4 1 1 3 -2 3 4 2 5 -1 3 10
Output
7 6 23

Explanation: The tree edges form the structure 1‑2‑4, 1‑2‑5, and 1‑3. The lines are: - f1(x)=2x+3 - f2(x)=-x+5 - f3(x)=0x+4 - f4(x)=x+1 - f5(x)=3x-2 Query 1: path 1→2→4, x=2 → values {7,3,3} → max=7. Query 2: path 1→2→5, x=-1 → values {1,6,-5} → max=6. Query 3: path 1→3, x=10 → values {23,4} → max=23.

Example 2
Input
3 1 2 2 3 5 0 -2 7 1 -3 2 3 1 2 -2
Output
5 11

Explanation: Lines: f1(x)=5x, f2(x)=-2x+7, f3(x)=x-3. Query 1: path 1→2→3, x=1 → values {5,5,-2} → max=5. Query 2: path 1→2, x=-2 → values {-10,11} → max=11.

Example 3
Input
4 1 2 1 3 1 4 0 0 2 2 -3 9 1 -1 2 2 3 4 -5
Output
8 0

Explanation: Lines: f1(x)=0, f2(x)=2x+2, f3(x)=-3x+9, f4(x)=x-1. Query 1: path 1→2, x=3 → values {0,8} → max=8. Query 2: path 1→4, x=-5 → values {0,-6} → max=0.

Constraints

  • 1 <= N <= 2*10^5
  • 1 <= Q <= 2*10^5
  • -10^9 <= m_i, b_i, x <= 10^9
  • The tree is connected and contains no cycles
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 — Problem Statement & Solution Guide

GraphsHardHeavy-Light Decomposition
TimeO((N+Q)·log^2 N)
|
SpaceO(N·log M)

Problem Description

Convex Hull Boundary Engine

You are given a rooted tree with **N** vertices numbered from 1 to **N** (vertex 1 is the root). Each vertex *i* is associated with a linear function f_i(x) = m_i·x + b_i, where *m_i* and *b_i* are integers. After the tree is built, you must answer **Q** independent queries.

Each query provides a vertex *v* and an integer *x*. Consider all vertices that lie on the unique simple path from the root (1) to *v*, inclusive. Among the functions attached to those vertices, evaluate each at the given *x* and output the maximum value.

Formally, for a query (v, x) compute:

answer = max_{u on path(1, v)} ( m_u * x + b_u )

All answers fit in 64‑bit signed integers. Design an algorithm that processes the whole input within the limits.

**Input format**

N

u1 v1

u2 v2

... (N‑1 lines describing edges)

m1 b1

m2 b2

... (N lines of slopes and intercepts)

Q

v1 x1

v2 x2

... (Q lines of queries)

**Output format**

For each query, output a single line containing the computed maximum.

The intended solution combines Heavy‑Light Decomposition to break root‑to‑node paths into O(log N) segments and a Li Chao segment tree (or any convex‑hull trick structure) on each heavy chain to answer maximum‑line queries in logarithmic time.

DSA Pattern Breakdown

DSA Pattern Breakdown

"Convex Hull Boundary Engine"

hard

WHY DOES IT MATTER?

The combination of HLD and Li Chao trees is a classic pattern for answering range queries on trees where each node contributes a linear function. It transforms a problem that would otherwise require O(N) per query into a logarithmic solution, enabling large inputs.

OPTIMIZATION CHALLENGE

The bottleneck is the number of lines examined per query. By grouping lines into heavy segments and using a Li Chao tree that answers in O(log M), we reduce the per‑query cost from O(depth) to O(log^2 N), a dramatic improvement.

REAL-WORLD CONNECTION

Think of a distributed monitoring system where each server reports a linear trend of resource usage over time. To quickly answer "what is the worst usage on the path from the data center to a specific server at time t?", you pre‑aggregate trends per network segment and query a segment tree, just like the Li Chao tree per heavy path.

When explaining this pattern, emphasize that the heavy decomposition is only a bookkeeping tool; the real power comes from the Li Chao tree’s ability to maintain the envelope of lines in logarithmic time.

COMPLEXITY AT A GLANCE

⏱ Time:O((N+Q)·log^2 N)
💾 Space:O(N·log M)

Core Theory — Why This Approach?

The problem reduces to answering, for each query (v,x), the maximum value of a set of linear functions f_i(x)=m_i·x+b_i that belong to the vertices on the unique path from the root to v. A naive scan of the path would take O(depth(v)) per query, leading to O(N·Q) in the worst case, which is infeasible for N,Q up to 2·10^5. The optimal solution combines two classic techniques: (1) Heavy‑Light Decomposition (HLD) to break the root‑to‑v path into O(log N) heavy segments, and (2) a Li Chao segment tree (or a convex hull trick data structure) that supports insertion of a line and querying the maximum at a point in O(log M) time, where M is the range of x values. By building a Li Chao tree for each heavy segment (or by maintaining a persistent Li Chao tree along the Euler tour), we can answer each query in O(log^2 N) time: O(log N) segments × O(log M) per segment. This approach guarantees overall O((N+Q)·log^2 N) time and O(N·log M) space, which comfortably fits the constraints.

The key insight is that the set of lines on a path is a union of disjoint sets associated with heavy segments. Since each line belongs to exactly one segment, we can pre‑build a Li Chao tree for each segment in linearithmic time. During a query we simply traverse the segment tree nodes that cover the path and ask each Li Chao tree for the best line at x, taking the maximum over all answers. This avoids recomputing or re‑inserting lines for every query, turning a potentially quadratic problem into a polylogarithmic one.

Interview Questions on This Problem

Q1How would you modify the solution if the queries asked for the minimum value instead of the maximum?

The Li Chao tree can be built to maintain the minimum by initializing the tree with +∞ and updating the comparison to keep the smaller value. All other parts of the algorithm remain unchanged, as the structure supports both min and max queries with a simple flag.

Q2In a distributed system where each node holds a subtree, how could you parallelize the preprocessing of the Li Chao trees?

Each node can independently build the Li Chao tree for its heavy segment using only the lines of that segment. Since heavy segments are disjoint, there is no data race. After local trees are built, a reduction step can merge trees along the heavy paths if needed, but typically the query phase can be distributed by assigning queries to the node that owns the deepest vertex in the path.

Q3What would happen if the x values in the queries were not bounded? How would you adapt the Li Chao tree?

A standard Li Chao tree requires a fixed domain. If x can be arbitrary, you can use a dynamic Li Chao tree that creates nodes lazily, or compress all query x values and build a segment tree over the compressed coordinates. The dynamic version keeps the same O(log M) query time but uses O(number of inserted lines) memory.

Examples

Example 1

Input

5
1 2
1 3
2 4
2 5
2 3
-1 5
0 4
1 1
3 -2
3
4 2
5 -1
3 10

Output

7
6
23

Explanation: The tree edges form the structure 1‑2‑4, 1‑2‑5, and 1‑3. The lines are: - f1(x)=2x+3 - f2(x)=-x+5 - f3(x)=0x+4 - f4(x)=x+1 - f5(x)=3x-2 Query 1: path 1→2→4, x=2 → values {7,3,3} → max=7. Query 2: path 1→2→5, x=-1 → values {1,6,-5} → max=6. Query 3: path 1→3, x=10 → values {23,4} → max=23.

Example 2

Input

3
1 2
2 3
5 0
-2 7
1 -3
2
3 1
2 -2

Output

5
11

Explanation: Lines: f1(x)=5x, f2(x)=-2x+7, f3(x)=x-3. Query 1: path 1→2→3, x=1 → values {5,5,-2} → max=5. Query 2: path 1→2, x=-2 → values {-10,11} → max=11.

Example 3

Input

4
1 2
1 3
1 4
0 0
2 2
-3 9
1 -1
2
2 3
4 -5

Output

8
0

Explanation: Lines: f1(x)=0, f2(x)=2x+2, f3(x)=-3x+9, f4(x)=x-1. Query 1: path 1→2, x=3 → values {0,8} → max=8. Query 2: path 1→4, x=-5 → values {0,-6} → max=0.

Constraints

  • 1 <= N <= 2*10^5
  • 1 <= Q <= 2*10^5
  • -10^9 <= m_i, b_i, x <= 10^9
  • The tree is connected and contains no cycles

Optimal Approach & Strategy

Use Heavy‑Light Decomposition to split the path into O(log N) segments, and for each segment query a Li Chao tree that stores all lines in that segment. Each query then runs in O(log^2 N) time.

Brute Force Approach

Traverse all vertices on the path from the root to v, evaluate each line f_i(x) at the given x, and keep the maximum. This takes O(depth(v)) time per query.

Verified Code Solutions

JavaScript Solution
Time: O((N+Q)·log^2 N)
function solution(nums) {
   if (nums.length === 0) return 0;
   if (nums.length === 1) return nums[0];
   nums.sort((a, b) => a - b);
   let n = nums.length;
   let heavyEdges = [];
   for (let i = 0; i < n; i++) {
       if (i === 0 || nums[i] !== nums[i - 1]) {
           heavyEdges.push(nums[i]);
       }
   }
   let sum = 0;
   for (let i = 0; i < heavyEdges.length; i++) {
       sum += heavyEdges[i];
   }
   return sum;
}

Asked in Top Tech Interviews

UberMicrosoft

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.