QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: trandkhoa

Posted at: 2026-06-04 00:52:22

Last updated: 2026-06-04 00:59:41

Back to Problem

New Editorial for Problem #13694

For each value g, the cities with indices $g,2g,3g,…$ will be connected together. There may exist pairs of cities whose gcd is greater than g, but since we process values of g from large to small, those gcd values have already been handled earlier. Based on this observation, we use parallel binary search to find the answer for each query.

Let day d correspond to value $g=M−d+1$

When processing day $d$, we merge all multiples of $g$:

for (int j = 2 * g; j <= n; j += g) {
    dsu.unite(g, j);
}

Time complexity: $O(n \log^2 m \cdot \alpha(n) + q \log m)$

Code:

struct DisjointSet {
    vector<int> par, num;
    int n;

    DisjointSet(int n) {
        this -> n = n;
    }

    void init() {
        par.assign(n + 5, 0);
        num.assign(n + 5, 0);
        iota(all(par), 0);
        fill(all(num), 1);
    }

    int findpar(int u) {
        return (par[u] == u ? u : par[u] = findpar(par[u]));
    }

    bool unite(int u, int v) {
        u = findpar(u);
        v = findpar(v);
        if (u == v) return false;

        if (num[u] < num[v]) swap(u,v);
        par[v] = u;
        num[u] += num[v];
        return true;
    }
};

struct infoQuery {
    int u, v;
};

constexpr int N = 1e5 + 1;
vector<int> canMid[N];
int n, q, m;

void solve() {
    cin >> n >> m >> q;
    vector<infoQuery> query(q + 1);

    For (i, 1, q) cin >> query[i].u >> query[i].v;

    vector<int> l(q + 1, 1), r(q + 1, m), ans(q + 1, m);

    For (i, 1, q) {
        if (query[i].u == query[i].v) {
            l[i] = m;
            r[i] = 1;
            ans[i] = 0;
        }
    }

    DisjointSet dsu(n);
    bool flag = true;
    while (flag) {
        flag = false;
        For (i, 1, q) {
            if (l[i] > r[i]) continue;
            flag = true;
            int mid = (l[i] + r[i]) >> 1;
            canMid[mid].pb(i);
        }

        if (!flag) break;

        dsu.init();
        For (i, 1, m) {
            int add = m - i + 1;
            for (int j = 2 * add; j <= n; j += add) {
                dsu.unite(add, j);
            }

            for (int id : canMid[i]) {
                auto &[u, v] = query[id];
                if (dsu.findpar(u) == dsu.findpar(v)) {
                    ans[id] = i;
                    r[id] = i - 1;
                } else {
                    l[id] = i + 1;
                }
            }

            vector<int>().swap(canMid[i]);
        }
    }

    For (i, 1, q) cout << ans[i] << endl;
}

Comments

No comments yet.