ICPC 2025
ICPC 2025

E. Delivery Service

The Intercity Caspian Package Company (ICPC) is starting a delivery service which will deliver pack- ages between various cities near the Caspian Sea. The company plans to hire couriers to carry packages between these cities. Each courier has a home city an...

Updated May 21, 2026
Track ICPC
Year 2025
Statement Text + PDF
TeXC++Statement textStatement PDF

Problem Statement

Formatted from the contest statement text, with sample tests broken out into copyable blocks.

Time limit 12 seconds

The Intercity Caspian Package Company (ICPC) is starting a delivery service which will deliver pack- ages between various cities near the Caspian Sea. The company plans to hire couriers to carry packages between these cities. Each courier has a home city and a destination city, and all couriers have exactly the same travel sched- ule: They leave their home city at 9:00, arrive at their destination city at 12:00, leave their destination city at 14:00 and return to their home city at 17:00. While couriers are in their home or destination cities, they can receive packages from and/or deliver packages to customers. They can also hand off to or receive packages from other couriers who are in that city at the same time. Since ICPC is a personal service, packages are never left in warehouses or other facilities to be picked up later – unless the pack- age has reached its destination, couriers have to either keep the package with themselves (during the day or during the night), or hand it off to another courier. The company will direct the couriers to hand off packages in such a way that any package can always be delivered to its destination. Or so it is hoped! We’ll say that two cities u and v are connected if it is possible to deliver a package from city u to city v as well as from v to u. To estimate the efficiency of their hiring process, the company would like to find, after each courier is hired, the number of pairs of cities (u, v) that are connected (1 ≤ u < v ≤ n).

Input

The first line of input contains two integers n and m, where n (2 ≤ n ≤ 2 · 105 ) is the number of cities, and m (1 ≤ m ≤ 4 · 105 ) is the number of couriers that will be hired. Couriers are numbered 1 to m, in the order they are hired. This is followed by m lines, the ith of which contains two distinct integers ai and bi (1 ≤ ai , bi ≤ n), denoting the home and destination cities, respectively, for courier i.

Output

Output m integers, denoting the number of pairs of connected cities after hiring the first 1, 2, . . . , m couriers.

Sample Tests

Sample 1
Sample Input
 4    4
 1    2
 2    3
 4    3
 4    2
Sample Output
1
2
4
6
  1. After the first courier is hired, cities 1 and 2 are connected.
  1. After the second courier is hired, cities 2 and 3 are connected. Note, however, that cities 1 and 3 are still not connected. Even though there’s a courier moving between cities 1 and 2, and a courier moving between cities 2 and 3, they never meet each other.
  1. After the third courier is hired, cities 3 and 4 are connected and cities 2 and 4 are connected. For example, one way to deliver a package from city 2 to city 4 is:
  • hand it to courier 2 in city 2 at 19:00;
  • the next day, courier 2 arrives in city 3 at 12:00, and hands the package to courier 3 who is also in city 3;
  • at 18:00, courier 3 delivers the package to city 4.
  1. After the fourth courier is hired, all six pairs of cities are connected.

Editorial

The solution write-up is rendered from the LaTeX source, with equations kept live through MathJax.

Key Observations

  • Create two vertices for every city $u$: $u_L$ for the times when couriers are in their home city, and $u_R$ for the times when couriers are in their destination city. A courier $(a,b)$ creates an undirected edge between $a_L$ and $b_R$.

  • A city is represented by the unordered pair of connected components containing its two copies. For example, if both copies lie in the same component $C$, the city corresponds to $(C,C)$. If the copies lie in two different components $C$ and $D$, the city corresponds to $(C,D)$.

  • Two cities $u$ and $v$ are connected if and only if their unordered component pairs intersect. Equivalently, the two cities share at least one DSU component among their four copies.

  • Therefore, if for each component $C$ we know how many cities touch $C$, then $\binom{\text{touch}(C)}{2}$ counts all city pairs that share component $C$. A pair of cities can be counted twice only when both are split across the same two components $(C,D)$, so those double counts must be subtracted once.

  • We can maintain this incrementally with a DSU. For each DSU component we store how many cities have both copies already inside that component, and a hash map counting how many cities are split between this component and another component. When two DSU components merge, only counters touching these two components change.

Algorithm

  1. Build a DSU on $2n$ vertices, one left copy and one right copy for each city. Initially, every city is split between its two singleton components, so we insert one count for the component pair $(u_L,u_R)$.

  2. Maintain two global totals:

    • tot1: the sum over all components $C$ of $\binom{z_C}{2}$, where $z_C$ is the number of cities that have at least one copy in $C$;

    • tot2: the sum over all unordered component pairs $(C,D)$ with $C \ne D$ of $\binom{y_{C,D}}{2}$, where $y_{C,D}$ is the number of cities split between $C$ and $D$.

    • The required answer is tot1 - tot2.

    • When a courier $(a,b)$ is added, unite the DSU components containing $a_L$ and $b_R$. Merge the smaller hash map into the larger one and update the two global totals in $O(\text{moved map entries})$ expected time. enumerate

      Correctness Proof

      We prove that the algorithm returns the correct answer.

      Lemma 1.

      Two cities $u$ and $v$ are connected if and only if the unordered pair of DSU components containing $(u_L,u_R)$ intersects the unordered pair containing $(v_L,v_R)$.

      Proof.

      Suppose the two unordered pairs intersect, and let $C$ be a common component. Then one copy of $u$ and one copy of $v$ both lie in $C$, so a package can be transferred through the sequence of couriers represented by paths inside $C$. Because the couriers are reversible over successive half-days, the same argument also gives a route in the opposite direction. Hence the cities are connected.

      Conversely, if the two unordered pairs are disjoint, then no copy of $u$ shares a connected component with any copy of $v$. No sequence of handoffs can ever move a package from a copy of $u$ to a copy of $v$, so the cities are not connected. □

      Lemma 2.

      At every moment, the DSU data stored by the program represents exactly:

      • for each component $C$, how many cities touch $C$;

      • for each unordered pair $(C,D)$ with $C \ne D$, how many cities are split between $C$ and $D$.

      Proof.

      Initially this is true by construction: each city touches exactly its two singleton components. A DSU union only changes data that involve one of the two merged components. The program removes the old contributions of those counts and inserts the new merged contributions. All other cities keep exactly the same touched components and split-component pair. Therefore the maintained counts are always exact. □

      Theorem.

      The algorithm outputs the correct answer for every valid input.

      Proof.

      By Lemma 2, after each courier is added the program knows the exact values of all $z_C$ and $y_{C,D}$. Summing $\binom{z_C}{2}$ over all components counts every pair of cities once for each shared component. By Lemma 1, a pair is connected exactly when it shares at least one component. A pair can be counted twice only if both cities are split across the same two components $(C,D)$, and the subtracted term $\binom{y_{C,D}}{2}$ removes exactly this double counting. Therefore tot1 - tot2 is exactly the number of connected city pairs. □

      Complexity Analysis

      Each DSU operation is nearly constant aside from hash-map merging. With the usual small-to-large strategy, every map entry is moved only $O(\log n)$ times, so the total expected running time is $O((n+m)\log n)$ and the memory usage is $O(n+m)$.

      Implementation Notes

      • The code stores only counts for split cities; cities whose two copies are already in the same DSU component are tracked by a separate counter per component.

      • Hash maps are merged from the smaller component into the larger one to keep the total work low.

Code

C++ solution used for this page.

C++

Clean code view with a raw-file link when you want the original source.

Raw file
#include <bits/stdc++.h>
using namespace std;

namespace {

long long c2(long long x) {
    return x * (x - 1) / 2;
}

struct DSU {
    vector<int> parent;
    vector<int> vertices_in_component;
    vector<int> internal_cities;
    vector<unordered_map<int, int>> split_to;
    long long total_shared_component_pairs = 0;
    long long total_double_counted_pairs = 0;

    explicit DSU(int n = 0) {
        init(n);
    }

    void init(int n) {
        parent.resize(n);
        vertices_in_component.assign(n, 1);
        internal_cities.assign(n, 0);
        split_to.assign(n, {});
        for (int i = 0; i < n; ++i) {
            parent[i] = i;
            split_to[i].reserve(2);
        }
        total_shared_component_pairs = 0;
        total_double_counted_pairs = 0;
    }

    int find(int x) {
        while (parent[x] != x) {
            parent[x] = parent[parent[x]];
            x = parent[x];
        }
        return x;
    }

    int touching_cities(int root) const {
        return vertices_in_component[root] - internal_cities[root];
    }

    void add_initial_city(int a, int b) {
        split_to[a][b] = 1;
        split_to[b][a] = 1;
    }

    void unite(int x, int y) {
        int a = find(x);
        int b = find(y);
        if (a == b) {
            return;
        }

        if (split_to[a].size() + (size_t)vertices_in_component[a] <
            split_to[b].size() + (size_t)vertices_in_component[b]) {
            swap(a, b);
        }

        total_shared_component_pairs -= c2(touching_cities(a));
        total_shared_component_pairs -= c2(touching_cities(b));

        int between = 0;
        auto it_ab = split_to[a].find(b);
        if (it_ab != split_to[a].end()) {
            between = it_ab->second;
            total_double_counted_pairs -= c2(between);
            split_to[a].erase(it_ab);
            split_to[b].erase(a);
        }

        parent[b] = a;
        vertices_in_component[a] += vertices_in_component[b];
        internal_cities[a] += internal_cities[b] + between;

        for (auto it = split_to[b].begin(); it != split_to[b].end(); ++it) {
            int other = it->first;
            int cnt = it->second;
            if (other == a) {
                continue;
            }

            int old = 0;
            auto it_old = split_to[a].find(other);
            if (it_old != split_to[a].end()) {
                old = it_old->second;
            }

            total_double_counted_pairs -= c2(old);
            total_double_counted_pairs -= c2(cnt);
            int merged = old + cnt;
            total_double_counted_pairs += c2(merged);

            split_to[a][other] = merged;
            split_to[other].erase(b);
            split_to[other][a] = merged;
        }
        split_to[b].clear();

        total_shared_component_pairs += c2(touching_cities(a));
    }

    long long answer() const {
        return total_shared_component_pairs - total_double_counted_pairs;
    }
};

}  // namespace

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    DSU dsu(2 * n);
    for (int city = 0; city < n; ++city) {
        dsu.add_initial_city(city, n + city);
    }

    for (int i = 0; i < m; ++i) {
        int a, b;
        cin >> a >> b;
        --a;
        --b;
        dsu.unite(a, n + b);
        cout << dsu.answer() << '\n';
    }

    return 0;
}

Source Files and Assets

Raw files are still available here when you want the original TeX, C++, or statement assets.

Show raw files