You are given an integer n and an undirected, weighted tree rooted at node 0 with n nodes numbered from 0 to n - 1. This is represented by a 2D array edges of length n - 1, where edges[i] = [ui, vi, wi] indicates an edge from node ui to vi with weight wi.
The weighted median node is defined as the first node x on the path from ui to vi such that the sum of edge weights from ui to x is greater than or equal to half of the total path weight.
You are given a 2D integer array queries. For each queries[j] = [uj, vj], determine the weighted median node along the path from uj to vj.
Return an array ans, where ans[j] is the node index of the weighted median for queries[j].
Example 1:
Input: n = 2, edges = [[0,1,7]], queries = [[1,0],[0,1]]
Output: [0,1]
Explanation:

| Query | Path | Edge Weights |
Total Path Weight |
Half | Explanation | Answer |
|---|---|---|---|---|---|---|
[1, 0] |
1 → 0 |
[7] |
7 | 3.5 | Sum from 1 → 0 = 7 >= 3.5, median is node 0. |
0 |
[0, 1] |
0 → 1 |
[7] |
7 | 3.5 | Sum from 0 → 1 = 7 >= 3.5, median is node 1. |
1 |
Example 2:
Input: n = 3, edges = [[0,1,2],[2,0,4]], queries = [[0,1],[2,0],[1,2]]
Output: [1,0,2]
Explanation:

| Query | Path | Edge Weights |
Total Path Weight |
Half | Explanation | Answer |
|---|---|---|---|---|---|---|
[0, 1] |
0 → 1 |
[2] |
2 | 1 | Sum from 0 → 1 = 2 >= 1, median is node 1. |
1 |
[2, 0] |
2 → 0 |
[4] |
4 | 2 | Sum from 2 → 0 = 4 >= 2, median is node 0. |
0 |
[1, 2] |
1 → 0 → 2 |
[2, 4] |
6 | 3 | Sum from 1 → 0 = 2 < 3.Sum from 1 → 2 = 2 + 4 = 6 >= 3, median is node 2. |
2 |
Example 3:
Input: n = 5, edges = [[0,1,2],[0,2,5],[1,3,1],[2,4,3]], queries = [[3,4],[1,2]]
Output: [2,2]
Explanation:

| Query | Path | Edge Weights |
Total Path Weight |
Half | Explanation | Answer |
|---|---|---|---|---|---|---|
[3, 4] |
3 → 1 → 0 → 2 → 4 |
[1, 2, 5, 3] |
11 | 5.5 | Sum from 3 → 1 = 1 < 5.5.Sum from 3 → 0 = 1 + 2 = 3 < 5.5.Sum from 3 → 2 = 1 + 2 + 5 = 8 >= 5.5, median is node 2. |
2 |
[1, 2] |
1 → 0 → 2 |
[2, 5] |
7 | 3.5 |
Sum from |
2 |
Constraints:
2 <= n <= 105edges.length == n - 1edges[i] == [ui, vi, wi]0 <= ui, vi < n1 <= wi <= 1091 <= queries.length <= 105queries[j] == [uj, vj]0 <= uj, vj < nedges represents a valid tree.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
We're looking for a special node in a tree that's the 'middle' when considering weights. The brute force way means checking every single node in the tree to see if it fits the criteria of being the weighted median by exhaustively exploring all possibilities.
Here's how the algorithm would work step-by-step:
def find_weighted_median_node_brute_force(tree, weights):
number_of_nodes = len(tree)
total_weight = sum(weights)
for potential_median_node in range(number_of_nodes):
weight_closer = 0
weight_further = 0
for other_node in range(number_of_nodes):
if other_node == potential_median_node:
continue
distance_to_median_node = calculate_distance(tree, potential_median_node, other_node)
# Determine if the other node is closer or further.
weight_closer_temp = 0
weight_further_temp = 0
other_distance = float('inf')
for intermediate_node in range(number_of_nodes):
if intermediate_node == other_node:
continue
intermediate_distance = calculate_distance(tree, other_node, intermediate_node)
if intermediate_distance < other_distance:
other_distance = intermediate_distance
node_to_median_distance = calculate_distance(tree, other_node, potential_median_node)
if node_to_median_distance <= other_distance:
weight_closer_temp += weights[other_node]
else:
weight_further_temp += weights[other_node]
weight_closer += weight_closer_temp
weight_further += weight_further_temp
# Check if the potential median is indeed the weighted median.
if weight_closer <= total_weight / 2 and weight_further <= total_weight / 2:
return potential_median_node
return -1
def calculate_distance(tree, node1, node2):
if node1 == node2:
return 0
queue = [(node1, 0)]
visited = {node1}
while queue:
current_node, distance = queue.pop(0)
if current_node == node2:
return distance
for neighbor in tree[current_node]:
if neighbor not in visited:
visited.add(neighbor)
queue.append((neighbor, distance + 1))
return float('inf')To find the weighted median node in a tree efficiently, we'll use a divide-and-conquer approach based on the concept of tree centroids. We'll repeatedly find centroids, which are nodes that split the tree into smaller, roughly equal parts considering node weights, and then strategically search within the relevant subtree.
Here's how the algorithm would work step-by-step:
def find_weighted_median_node(graph, weights):
number_of_nodes = len(graph)
def calculate_total_weight(subtree_root, parent):
total_weight = weights[subtree_root]
for neighbor in graph[subtree_root]:
if neighbor != parent:
total_weight += calculate_total_weight(neighbor, subtree_root)
return total_weight
total_weight = sum(weights)
def find_centroid(subtree_root, parent, subtree_weight):
is_centroid = True
subtree_size = weights[subtree_root]
for neighbor in graph[subtree_root]:
if neighbor != parent:
neighbor_subtree_weight = calculate_subtree_weight(neighbor, subtree_root)
if neighbor_subtree_weight > subtree_weight / 2:
is_centroid = False
return find_centroid(neighbor, subtree_root, subtree_weight)
subtree_size += neighbor_subtree_weight
if is_centroid:
return subtree_root
def calculate_subtree_weight(subtree_root, parent):
weight = weights[subtree_root]
for neighbor in graph[subtree_root]:
if neighbor != parent:
weight += calculate_subtree_weight(neighbor, subtree_root)
return weight
current_subtree_root = 0
nodes_in_current_subtree = list(range(number_of_nodes))
while True:
subtree_weight = sum([weights[node] for node in nodes_in_current_subtree])
centroid = find_centroid(current_subtree_root, -1, subtree_weight)
# Check if the centroid is the weighted median
less_than_centroid_weight = 0
greater_than_centroid_weight = 0
for i in range(number_of_nodes):
if i != centroid:
if weights[i] <= weights[centroid]:
less_than_centroid_weight += weights[i]
else:
greater_than_centroid_weight += weights[i]
if less_than_centroid_weight <= total_weight / 2 and greater_than_centroid_weight <= total_weight / 2:
return centroid
# Determine which subtree to focus on
heavy_subtree = -1
heavy_subtree_weight = 0
for neighbor in graph[centroid]:
neighbor_subtree_weight = calculate_subtree_weight(neighbor, centroid)
if neighbor_subtree_weight > heavy_subtree_weight:
heavy_subtree_weight = neighbor_subtree_weight
heavy_subtree = neighbor
if heavy_subtree == -1:
return centroid
#Narrow down the search space to the heavy subtree
new_nodes_in_subtree = []
def dfs(node, parent):
new_nodes_in_subtree.append(node)
for neighbor in graph[node]:
if neighbor != parent:
dfs(neighbor,node)
new_nodes_in_subtree = []
dfs(heavy_subtree, centroid)
nodes_in_current_subtree = new_nodes_in_subtree
current_subtree_root = nodes_in_current_subtree[0]| Case | How to Handle |
|---|---|
| Null or empty tree | Return null if the tree is null or empty as there is no median node. |
| Single node tree | Return the single node itself as it is trivially the weighted median. |
| Tree with all weights equal to zero | Return any node; typically the root is a good default in this edge case, as all nodes are equally valid. |
| Tree with negative weights (if weights can be negative) | Handle negative weights based on problem constraints, potentially normalizing them to positive values if necessary. |
| Very large weights causing integer overflow | Use appropriate data types (e.g., long) or consider normalization if overflow is a concern. |
| Skewed tree with the majority of the weight concentrated in one subtree. | Ensure that the algorithm efficiently traverses such skewed trees without excessive recursion depth or performance degradation. |
| Disconnection of nodes from root due to weight adjustments. | The chosen solution should correctly handle potentially orphaned nodes (disconnected from the root after weight adjustment) during the search for the weighted median. |
| Nodes with duplicate weight values | The solution must correctly account for and distinguish between nodes with same weight values to identify the true weighted median. |