Graph Connectivity With Threshold

hard graph union find math

Problem

There are n cities labeled 1 to n. Two cities x and y are connected directly if they share a common divisor strictly greater than threshold. For each query [a, b], return whether cities a and b are connected (directly or indirectly).

For every divisor d > threshold, all multiples of d (d, 2d, 3d, …) share that divisor, so union them together. Then each query is just a same-root check.

Inputn = 6, threshold = 2, queries = [[1,4],[2,5],[3,6]]
Output[false, false, true]
Only divisors 3,4,5,6 exceed 2. Multiples of 3 → {3,6}; multiples of others are singletons. So 3 and 6 are connected; 1 and others stay isolated.

def are_connected(n, threshold, queries):
    parent = list(range(n + 1))
    def find(x):
        while parent[x] != x:
            parent[x] = parent[parent[x]]
            x = parent[x]
        return x
    def union(a, b):
        parent[find(a)] = find(b)
    for d in range(threshold + 1, n + 1):
        multiple = 2 * d
        while multiple <= n:
            union(d, multiple)
            multiple += d
    return [find(a) == find(b) for a, b in queries]
function areConnected(n, threshold, queries) {
  const parent = Array.from({ length: n + 1 }, (_, i) => i);
  function find(x) {
    while (parent[x] !== x) { parent[x] = parent[parent[x]]; x = parent[x]; }
    return x;
  }
  function union(a, b) { parent[find(a)] = find(b); }
  for (let d = threshold + 1; d <= n; d++) {
    for (let m = 2 * d; m <= n; m += d) {
      union(d, m);
    }
  }
  return queries.map(([a, b]) => find(a) === find(b));
}
class Solution {
    int[] parent;
    int find(int x) {
        while (parent[x] != x) { parent[x] = parent[parent[x]]; x = parent[x]; }
        return x;
    }
    void union(int a, int b) { parent[find(a)] = find(b); }
    public List<Boolean> areConnected(int n, int threshold, int[][] queries) {
        parent = new int[n + 1];
        for (int i = 0; i <= n; i++) parent[i] = i;
        for (int d = threshold + 1; d <= n; d++)
            for (int m = 2 * d; m <= n; m += d)
                union(d, m);
        List<Boolean> ans = new ArrayList<>();
        for (int[] q : queries) ans.add(find(q[0]) == find(q[1]));
        return ans;
    }
}
class Solution {
public:
    vector<int> parent;
    int find(int x) {
        while (parent[x] != x) { parent[x] = parent[parent[x]]; x = parent[x]; }
        return x;
    }
    void uni(int a, int b) { parent[find(a)] = find(b); }
    vector<bool> areConnected(int n, int threshold, vector<vector<int>>& queries) {
        parent.resize(n + 1);
        for (int i = 0; i <= n; i++) parent[i] = i;
        for (int d = threshold + 1; d <= n; d++)
            for (int m = 2 * d; m <= n; m += d)
                uni(d, m);
        vector<bool> ans;
        for (auto& q : queries) ans.push_back(find(q[0]) == find(q[1]));
        return ans;
    }
};
Time: O(n log n · α + Q) Space: O(n)