// union find implementation
class UF {
// vi p : p[i] stores the index of parent item (i.e. the immediate parent of
// item i), if p[i] = i, item i is the representative item of a certain
// disjoint set.
// vi r : r[i] is the UPPER BOUND of the height of the tree rooted at i
vi p, r;
public:
UF(int n) {
p.assign(n, 0);
iota(p.begin(), p.end(), 0);
r.assign(n, 0);
}
int find(int i) { return (p[i] == i) ? i : (p[i] = find(p[i])); }
bool same(int i, int j) { return find(i) == find(j); }
void merge(int i, int j) {
if (!same(i, j)) {
int x = find(i), y = find(j);
if (r[x] > r[y]) {
p[y] = x;
} else {
p[x] = y;
if (r[x] == r[y]) {
r[y]++;
}
}
}
}
};