Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 26 – Dynamic programming: advanced patterns

Rerooting: answers for every root

The total distance from every village to all others in a tree of roads: the problem, a search from every village, and the signal for rerooting.

  • Advanced
  • 35 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free intro, Pro: 7 of 35 minutes free
Free: Total distances in a district of villages · The brute force: a search from every village · What to notice. With a pass: the other 8 sections and 3 interview answers, about 28 minutes.

What you will learn

  • Compute an answer for every possible root of a tree in O(n) in all
  • Combine a first pass that gathers subtree facts and a second pass that moves the root one edge at a time
  • Apply rerooting to sums of distances, to road lengths and to villages with populations
  • Compute the farthest node from every node, where a maximum cannot be undone like a sum
  • Choose the village that minimises total travel, and prove which one it is

Before you start

What you’ll learn · Before you start

What you will learn

  • Compute an answer for every possible root of a tree in O(n) in all
  • Combine a first pass that gathers subtree facts and a second pass that moves the root one edge at a time
  • Apply rerooting to sums of distances, to road lengths and to villages with populations
  • Compute the farthest node from every node, where a maximum cannot be undone like a sum
  • Choose the village that minimises total travel, and prove which one it is

Before you start

On this page

Rerooting answers a question for every node of a tree as if that node were the root, in O(n) in all instead of O(n) per root. A first pass from one fixed root gathers facts about every subtree; a second pass moves the root across one edge at a time and adjusts the answer in O(1) per edge. The standard example is the sum of distances in a tree: for every node, the total distance to all the other nodes. A search from every node takes O(n²); rerooting takes two passes.

Total distances in a district of villages

A district has n villages joined by n − 1 roads, each 1 km long, so that there is exactly one route between any two villages. For every village, return the total distance from it to all the other villages. Limits: 1 ≤ n ≤ 10⁵, and the roads come as pairs of village numbers, in any order and direction.

  • The seven villages, with roads 0–1, 1–2, 1–3, 3–4, 3–5 and 5–6: [15, 10, 15, 9, 14, 12, 17]. Village 3 is the best meeting point.
  • A line of four villages: [6, 4, 4, 6].
  • A star of five villages around village 0: [4, 7, 7, 7, 7].
Seven villages in a tree with each total distance; moving from village 1 to village 3 turns 10 into 10 − 4 + 3 = 9.village 0: 15 kmvillage 1: 10 kmvillage 3: 9 kmvillage 2: 15 kmvillage 5: 12 kmvillage 4: 14 kmvillage 6: 17 km

The seven villages, split by the road from village 1 to village 3

Text description of the diagram

The diagram shows seven villages joined by six roads of 1 km each, drawn as a tree with village 0 at the top. Every village is labelled with its total distance to the other six.

  • Village 0 (15 km) is joined to village 1 (10 km).
  • Village 1 is joined to village 2 (15 km) and, by a thick road, to village 3 (9 km).
  • Village 3 is joined to village 4 (14 km) and village 5 (12 km), and village 5 to village 6 (17 km).

Villages 3, 4, 5 and 6, the four on village 3's side of the thick road, have dashed borders, and village 3 also has a double border.

Moving the meeting point from village 1 to village 3 brings the four villages of 3's side 1 km closer and takes the three villages of the other side 1 km farther, so village 3's total is village 1's total, 10, minus 4, plus 3: 9, the smallest of all seven.

The brute force: a search from every village

A breadth-first search from one village finds its distance to every other village in O(n), so n searches give every total in O(n²).

A search from every village, with the village visits counted

free/brute_force.py

"""The total distance from every village to all others by brute force: one breadth-first search per village."""
import random

from villages import distances_from, neighbours, random_district


def totals_brute(n, roads):
    near = neighbours(n, roads)
    visits = 0
    totals = []
    for start in range(n):
        dist = distances_from(near, start)
        visits += n  # one search reaches every village once
        totals.append(sum(dist))
    return totals, visits


DISTRICTS = {
    "the seven villages": (7, [(0, 1), (1, 2), (1, 3), (3, 4), (3, 5), (5, 6)]),
    "a line of four villages": (4, [(0, 1), (1, 2), (2, 3)]),
    "a star of five villages around village 0": (5, [(0, 1), (0, 2), (0, 3), (0, 4)]),
    "one village": (1, []),
}
for label, (n, roads) in DISTRICTS.items():
    totals, visits = totals_brute(n, roads)
    print(f"{label}: {totals} after {visits:,} village visits")

rng = random.Random(14)
for n in (500, 1_000, 2_000):
    _, visits = totals_brute(n, random_district(rng, n))
    print(f"a random district of {n:,} villages: {visits:,} village visits")

Output

the seven villages: [15, 10, 15, 9, 14, 12, 17] after 49 village visits
a line of four villages: [6, 4, 4, 6] after 16 village visits
a star of five villages around village 0: [4, 7, 7, 7, 7] after 25 village visits
one village: [0] after 1 village visits
a random district of 500 villages: 250,000 village visits
a random district of 1,000 villages: 1,000,000 village visits
a random district of 2,000 villages: 4,000,000 village visits

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute_force.py

free/villages.py

"""Districts of villages joined by roads of 1 km that form a tree: neighbour lists, searches and random districts."""
from collections import deque


def neighbours(n, roads):
    """The villages one road away from each village."""
    near = [[] for _ in range(n)]
    for u, v in roads:
        near[u].append(v)
        near[v].append(u)
    return near


def distances_from(near, start):
    """Breadth-first search from one village: the distance in km to every village."""
    dist = [-1] * len(near)
    dist[start] = 0
    queue = deque([start])
    while queue:
        u = queue.popleft()
        for v in near[u]:
            if dist[v] < 0:
                dist[v] = dist[u] + 1
                queue.append(v)
    return dist


def random_district(rng, n):
    """n villages with random names 0..n-1; each joins an earlier one; roads in random order and direction."""
    label = list(range(n))
    rng.shuffle(label)
    roads = [(label[rng.randrange(v)], label[v]) for v in range(1, n)]
    roads = [(v, u) if rng.random() < 0.5 else (u, v) for u, v in roads]
    rng.shuffle(roads)
    return roads

The visits come to exactly n²: 4,000,000 for 2,000 villages. At 10⁵ villages that is 10¹⁰ visits, more than a minute even in compiled code and hours in Python.

What to notice

  • Moving the meeting point along one road changes every distance by exactly 1 km. Going from village p to its neighbour c, every village on c’s side of the road gets 1 km closer and every other village 1 km farther.
  • So c’s total follows from p’s total in one step, once you know how many villages lie on c’s side: on the diagram, 10 − 4 + 3 = 9.
  • Those counts are subtree sizes, and one pass from any fixed village gives them for every road at once.
  • Answers built from a maximum fit the same shape, such as the farthest village from each village, with more bookkeeping, because a maximum cannot be undone the way a sum can.

Two passes: sizes on the way up, totals on the way down Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Why one road changes the total by n − 2 · size(c), proved
    • A dry run on the seven villages
  • The code in Python, JavaScript, Java, C++ and Go
    • Totals that need 64 bits
    • A C++23 trap: a helper named print
  • Measured: two passes against a search from every village
  • When nothing can be subtracted: the farthest village
  • Edge cases and five common bugs
  • Variants: road lengths, people and the best village for a clinic
    • Exercise: the total distance from every village
    • The total distance from every village
    • A practice set with answers
  • Check yourself
    • Follow-up questions, answered
  • Interview questions
    • A tree network has 200,000 nodes. For every node, report the sum of its distances to all other nodes, in O(n) in total. Derive how the answer changes across one edge, and say which integer types you need.
    • For every node of a tree with 100,000 nodes, find the distance to its farthest node, in O(n). Explain why the subtraction that works for sums of distances does not work here, and what you keep instead.
    • Villages with populations form a tree of roads with lengths. Choose the village for one clinic that minimises the total person-km travelled. Show how to compute it in O(n), and prove which village wins without comparing every total.
  • Key takeaways

9 runnable examples (C++, Go, Java, JavaScript, Python, distances.py, drills.py, farthest.py, villages.py) · 1 exercise with sample tests · 3 interview answers · about 22 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.