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 22 – Union-find (disjoint sets)

Offline queries sorted by threshold

Answer many questions of whether two places connect on links below a limit by sorting links and questions together: the problem, brute force and signal.

  • 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: 8 of 35 minutes free
Free: The problem: buses on flooded roads · The brute force, and why it fails at this size · What to notice. With a pass: the other 12 sections and 3 interview answers, about 27 minutes.

What you will learn

  • Sort links and questions by threshold and answer every question in one pass
  • Answer whether two places connect using only links below a limit
  • Write each answer back in the order the questions were asked
  • Prove that the union-find holds exactly the links below the current limit
  • Answer the same questions one at a time with a merge tree built from the links

Before you start

What you’ll learn · Before you start

What you will learn

  • Sort links and questions by threshold and answer every question in one pass
  • Answer whether two places connect using only links below a limit
  • Write each answer back in the order the questions were asked
  • Prove that the union-find holds exactly the links below the current limit
  • Answer the same questions one at a time with a merge tree built from the links

Before you start

On this page

Offline queries sorted by threshold answer many questions of one kind at once: can u reach v using only links whose weight is below a limit? When every question is known before the first answer is due, the questions may be answered in any order. Sorted by limit, each question allows every link the previous one allowed and perhaps more, so a single union-find can grow from one question to the next instead of being rebuilt, and each answer is two finds. When the questions arrive one at a time instead, a merge tree built from the sorted links answers each one alone. A search per question, the obvious method, does the whole network’s work again for every question.

The problem: buses on flooded roads

After a storm, a city’s roads are flooded to different depths. The city has n junctions, numbered 0 to n − 1, and roads (a, b, depth) that join two junctions both ways. A bus with a limit of L centimetres can use a road only when the water on it is strictly below L. Each question (u, v, L) asks whether a bus with limit L can get from u to v; answer them all, in the order they were asked. Limits: n, the number of roads and the number of questions are each at most 100,000, and depths and limits are at most 10⁹.

  1. Roads 0–1 (30), 1–2 (10), 2–3 (45), 0–3 (60) and 3–4 (20) answer (0, 2, 31), (0, 3, 45), (0, 3, 46), (2, 4, 21) and (4, 4, 1) with yes, no, yes, no and yes. A limit of 45 is not enough for the 45 cm road, and a bus is always at its own junction.
  2. Two roads between 0 and 1, of 50 and 20 cm, answer (0, 1, 21) with yes and (1, 0, 20) with no.
Five junctions and five roads with water depths 30, 10, 45, 60 and 20 cm; for a limit of 46 cm only the 60 cm road is too deep.Water on each road, and a limit of 46 cm30 cm10 cm45 cm60 cm20 cm01234Solid: water below 46 cm, the bus can pass.Dashed: 60 cm, too deep. From 0 to 3 the bus goesthrough 1 and 2; the 45 cm road needs a limit of 46,because a road as deep as the limit is not usable.

The first example, for a bus with a limit of 46 cm

Text description of the diagram

Junctions 0, 1 and 2 are in a row along the top, and junctions 4 and 3 along the bottom, with 3 under 2. The roads and the water on them:

  1. 0 to 1: 30 cm.
  2. 1 to 2: 10 cm.
  3. 2 to 3: 45 cm.
  4. 0 to 3, a long diagonal: 60 cm.
  5. 3 to 4: 20 cm.

For a bus with a limit of 46 cm, every road with water below 46 cm is drawn solid and the 60 cm road is dashed, because it is too deep. The bus can go from 0 to 3 through 1 and 2. With a limit of 45 cm it could not: the 2 to 3 road is exactly 45 cm deep, and a road as deep as the limit is not usable.

The brute force, and why it fails at this size

For each question, search from u over the roads whose water is below its limit, and see whether the search reaches v:

A breadth-first search for every question, with the road looks counted Python · brute/brute_force.py
# The brute force: for every question, a breadth-first search over the roads whose water is below the bus's limit.
# Correct by construction, so it is what faster code is checked against.
import random
from collections import deque


def can_travel_brute(n, roads, questions):
    """For each question (u, v, limit): can a bus reach v from u on roads whose depth is strictly below the limit?"""
    links = [[] for _ in range(n)]
    for a, b, depth in roads:
        links[a].append((b, depth))
        links[b].append((a, depth))
    answers, looks = [], 0
    for u, v, limit in questions:
        seen, queue = {u}, deque([u])
        while queue and v not in seen:
            for w, depth in links[queue.popleft()]:
                looks += 1
                if depth < limit and w not in seen:
                    seen.add(w)
                    queue.append(w)
        answers.append(v in seen)
    return answers, looks


roads = [(0, 1, 30), (1, 2, 10), (2, 3, 45), (0, 3, 60), (3, 4, 20)]
questions = [(0, 2, 31), (0, 3, 45), (0, 3, 46), (2, 4, 21), (4, 4, 1)]
answers, looks = can_travel_brute(5, roads, questions)
print("example 1:", answers, f"after {looks} road looks")
answers, looks = can_travel_brute(2, [(0, 1, 50), (0, 1, 20)], [(0, 1, 21), (1, 0, 20)])
print("example 2:", answers, f"after {looks} road looks")

rng = random.Random(15)
for n in (500, 1_000, 2_000):
    roads = [(i, rng.randrange(i), rng.randint(1, 100)) for i in range(1, n)]  # a random tree of roads
    questions = [(rng.randrange(n), rng.randrange(n), 101) for _ in range(n)]  # every road usable: worst case
    _, looks = can_travel_brute(n, roads, questions)
    print(f"{n:>5,} junctions, roads and questions: {looks:>9,} road looks")

Output

example 1: [True, False, True, False, True] after 20 road looks
example 2: [True, False] after 4 road looks
  500 junctions, roads and questions:   210,211 road looks
1,000 junctions, roads and questions:   890,910 road looks
2,000 junctions, roads and questions: 3,557,726 road looks

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

When every road is usable, each search can cover the whole network, so doubling n and the number of questions multiplies the work by four. At the limits that is up to 10⁵ questions × 2 × 10⁵ road looks, about 2 × 10¹⁰: hours of Python, and still minutes of C++.

What to notice

  • All the questions are given before any answer is needed, so they may be answered in any order.
  • A higher limit never removes a road: the roads usable at one limit are usable at every higher one.
  • A question needs only whether two junctions are connected, which is what a union-find answers.

Sorting both lists, step by step Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Why every answer is right
  • A dry run on the first example
  • The code in five languages
  • The sorted pass against a search per question, measured
  • Edge cases and common bugs
  • When questions arrive one at a time
  • Variants: junctions reached, and limits that run the other way
    • Checked against a search per question
  • Exercise: journeys below a limit
    • Journeys on roads below a limit
  • A practice set with sample answers
  • Check yourself
  • Interview questions
    • Why does sorting the questions by their limit let one union-find answer all of them, and why must each question keep its original position?
    • The bus questions now arrive one at a time on a dispatch screen, and each must be answered before the next is read. The roads are known in advance: 10⁵ junctions, 10⁵ roads and 10⁵ questions. What do you build, and what does each question cost?
    • For each of 10⁵ pairs of junctions, report the smallest whole-number limit that lets a bus travel between them, or −1 if no limit does. How do you answer all the pairs without a search for each?
    • For each of 10⁵ limits, how many unordered pairs of different junctions could a bus with that limit travel between? The network has 10⁵ junctions and 2 × 10⁵ roads.
  • Key takeaways

8 runnable examples (C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 23 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.