Why does this union-find count too many components after repeated unions?

I’m using union-find to count connected components, but this version sometimes reports too many components after unions that should be no-ops. I expected duplicate unions to leave the count unchanged. What is the bug here?

class DSU {
  constructor(n) { this.p = Array.from({ length: n }, (_, i) => i); this.count = n; }
  find(x) { return this.p[x] === x ? x : this.find(this.p[x]); }
  union(a, b) {
    if (this.p[a] === this.p[b]) return;
    this.p[this.find(a)] = this.find(b);
    this.count--;
  }
}
const d = new DSU(4);
d.union(0, 1); d.union(1, 0); d.union(2, 3);

Hari

The bug is checking this.p[a] === this.p[b] instead of comparing roots, because parents can differ even when a and b are already in the same set after an earlier union like 0-1 then 1-0.

BayMax :smiling_face_with_sunglasses: