Redundant Connection II

hard union find graph

Problem

Rooted tree + one extra edge. Find the redundant edge to remove (last by input order if multiple).

Inputedges=[[1,2],[1,3],[2,3]]
Output[2,3]
Node 3 has two parents (1 and 2); remove the later one.

def find_redundant(edges):
    n = len(edges); parent = [0] * (n + 1); cand1 = cand2 = None
    for e in edges:
        if parent[e[1]] != 0: cand1 = [parent[e[1]], e[1]]; cand2 = e; e[0] = e[1] = -1
        else: parent[e[1]] = e[0]
    p = list(range(n + 1))
    def f(x):
        while p[x] != x: p[x] = p[p[x]]; x = p[x]
        return x
    for u, v in edges:
        if u < 0: continue
        ru, rv = f(u), f(v)
        if ru == rv: return cand1 if cand1 else [u, v]
        p[ru] = rv
    return cand2
function findRedundantDirectedConnection(edges) {
  const n = edges.length; const par = new Array(n + 1).fill(0); let c1 = null, c2 = null;
  const E = edges.map(e => e.slice());
  for (const e of E) {
    if (par[e[1]]) { c1 = [par[e[1]], e[1]]; c2 = e.slice(); e[0] = e[1] = -1; }
    else par[e[1]] = e[0];
  }
  const p = Array.from({length: n + 1}, (_, i) => i);
  const f = x => { while (p[x] !== x) { p[x] = p[p[x]]; x = p[x]; } return x; };
  for (const [u, v] of E) {
    if (u < 0) continue;
    const ru = f(u), rv = f(v);
    if (ru === rv) return c1 || [u, v];
    p[ru] = rv;
  }
  return c2;
}
int[] findRedundantDirectedConnection(int[][] edges) {
    int n = edges.length; int[] par = new int[n + 1], c1 = null, c2 = null;
    int[][] E = new int[n][]; for (int i = 0; i < n; i++) E[i] = edges[i].clone();
    for (int[] e : E) {
        if (par[e[1]] != 0) { c1 = new int[]{par[e[1]], e[1]}; c2 = e.clone(); e[0] = e[1] = -1; }
        else par[e[1]] = e[0];
    }
    int[] p = new int[n + 1]; for (int i = 0; i <= n; i++) p[i] = i;
    for (int[] e : E) {
        if (e[0] < 0) continue;
        int ru = find(p, e[0]), rv = find(p, e[1]);
        if (ru == rv) return c1 != null ? c1 : new int[]{e[0], e[1]};
        p[ru] = rv;
    }
    return c2;
}
int find(int[] p, int x) { while (p[x] != x) { p[x] = p[p[x]]; x = p[x]; } return x; }
int find(vector& p, int x) { while (p[x] != x) { p[x] = p[p[x]]; x = p[x]; } return x; }
vector findRedundantDirectedConnection(vector>& edges) {
    int n = edges.size(); vector par(n + 1, 0); vector c1, c2;
    auto E = edges;
    for (auto& e : E) {
        if (par[e[1]]) { c1 = {par[e[1]], e[1]}; c2 = e; e[0] = e[1] = -1; }
        else par[e[1]] = e[0];
    }
    vector p(n + 1); iota(p.begin(), p.end(), 0);
    for (auto& e : E) {
        if (e[0] < 0) continue;
        int ru = find(p, e[0]), rv = find(p, e[1]);
        if (ru == rv) return !c1.empty() ? c1 : vector{e[0], e[1]};
        p[ru] = rv;
    }
    return c2;
}
Time: O(n·α(n)) Space: O(n)