Sum of Distances in Tree

Updated on 26 June, 2025
Sum of Distances in Tree header image

Problem Statement

In an undirected connected tree with n nodes labeled from 0 to n - 1, connected by n - 1 edges, your task is to compute specific values for each node based on the node's connectivity and tree structure. Each tree edge connects two nodes ai and bi, as specified by an array edges where each element edges[i] is a pair [ai, bi].

The goal is to return an array answer where each item answer[i] contains the total sum of distances from the i-th node to every other node in the tree. In other words, for each node, calculate the sum of the shortest paths from this node to every other node and populate these sums in the resultant array.

Examples

Example 1

Input:

n = 6, edges = [[0,1],[0,2],[2,3],[2,4],[2,5]]

Output:

[8,12,6,10,10,10]

Explanation:

The tree is shown above.
We can see that dist(0,1) + dist(0,2) + dist(0,3) + dist(0,4) + dist(0,5)
equals 1 + 1 + 2 + 2 + 2 = 8.
Hence, answer[0] = 8, and so on.

Example 2

Input:

n = 1, edges = []

Output:

[0]

Example 3

Input:

n = 2, edges = [[1,0]]

Output:

[1,1]

Constraints

  • 1 <= n <= 3 * 104
  • edges.length == n - 1
  • edges[i].length == 2
  • 0 <= ai, bi < n
  • ai != bi
  • The given input represents a valid tree.

Approach and Intuition

  1. This problem requires an understanding of tree data structures, how to traverse them, and calculate distances between nodes in an efficient manner.
  2. Given the constraints on node numbers (n <= 30,000), an efficient algorithm must avoid direct path calculation between all pairs, as that would be computationally expensive.
  3. Efficient traversal methods such as Depth-First Search (DFS) can be employed to calculate distances from a root node to all other nodes initially.

Here’s how we can visualize and solve the problem:

  • Initial Setup: Convert the edge list into an adjacency list for easy access during traversal.
  • First Pass (Rooting the Tree):
    • Choose any node as the root. Often, node 0 is used as a convenient root.
    • Apply DFS/BFS from the root to calculate initial distances to all nodes and also count the number of nodes in each subtree rooted at every node.
  • Second Pass (Using Parent Distances):
    • Use the distances computed from the root node to deduce distances for the rest of the nodes using the properties of the tree:
      • If you know the distance from a node A to all other nodes, and if you move to its child B, the only changes in distances are for the nodes in subtree rooted at B and all other nodes.
      • Specifically, moving from A to B, the nodes in the subtree of B get closer by 1, and all others get farther by 1.
    • This can help compute distances for each node based on already computed distances for its parent, significantly lowering the computational overhead.

Given examples show how the distances sum up for small-sized trees and how sum of distances remains constant when only two nodes are connected. Through this intuitive yet analytic approach, each node’s distances to others are effectively and efficiently computed, abiding by given constraints and expected tree characteristics.

Solutions

  • Java
java
class TreeCalculator {
    int[] result, subtreeSize;
    List<Set<Integer>> treeStructure;
    int totalNodes;
    public int[] calculateDistanceSum(int totalNodes, int[][] edges) {
        this.totalNodes = totalNodes;
        treeStructure = new ArrayList<Set<Integer>>();
        result = new int[totalNodes];
        subtreeSize = new int[totalNodes];
        Arrays.fill(subtreeSize, 1);

        for (int i = 0; i < totalNodes; ++i)
            treeStructure.add(new HashSet<Integer>());
        for (int[] edge: edges) {
            treeStructure.get(edge[0]).add(edge[1]);
            treeStructure.get(edge[1]).add(edge[0]);
        }
        postOrderTraverse(0, -1);
        preOrderTraverse(0, -1);
        return result;
    }

    public void postOrderTraverse(int node, int parent) {
        for (int neighbor: treeStructure.get(node)) {
            if (neighbor != parent) {
                postOrderTraverse(neighbor, node);
                subtreeSize[node] += subtreeSize[neighbor];
                result[node] += result[neighbor] + subtreeSize[neighbor];
            }
        }
    }

    public void preOrderTraverse(int node, int parent) {
        for (int neighbor: treeStructure.get(node)) {
            if (neighbor != parent) {
                result[neighbor] = result[node] - subtreeSize[neighbor] + totalNodes - subtreeSize[neighbor];
                preOrderTraverse(neighbor, node);
            }
        }
    }
}

Explore a Java solution for calculating the sum of distances in a tree given total nodes and edges. This approach uses two main techniques: post-order and pre-order traversal to computationally understand tree structures efficiently.

  • Start by defining a TreeCalculator class which includes array structures to store results, subtree sizes, and a list representation of the tree connectivity.
  • Implement a method calculateDistanceSum that initializes these structures and processes the input edges to build an undirected tree. This method also calls the traversal functions.
  • The postOrderTraverse function is pivotal for calculating the size of each subtree and the initial result for each node recursively. It progresses from children to the parent, which helps in accumulating subtree sizes and the result for distance calculations.
  • The preOrderTraverse function utilizes the results from the post-order phase to adjust the result array. It calculates distances leveraging properties derived from the tree structure, where changes in subtree size affect overall distances to other nodes.
  • Both traversal methods use recursion to achieve depth-first processing from node to node, ensuring all nodes in the tree are visited and processed according to both their parent and child relationships.
  • The final output is the result array containing the sum of distances from each node to all other nodes in the tree.

This solution effectively uses tree traversal techniques to handle distance calculations in trees, ensuring optimal performance suitable for large datasets by employing an adjacency list representation of the tree structure and recursive depth-first algorithms.

Comments

No comments yet.