// 找 x 的根节点 intfind(int x) { // 判断 x 的父节点 p[x] 是否等于自己, 如果是,则 x=p[x]为根节点,直接返回p[x] // 如果不是,则继续找p[x]的根节点并返回,即 p[x] = find(p[x]) if (p[x] != x) p[x] = find(p[x]); return p[x]; }
longlongcountPairs(int n, vector<vector<int>>& edges){ // 不连通的数量 = 全集-连通的数量: // 不能到达的点对数 = C n 2 - 所有连通块中连通的点对数量(所有连通块中 连通块节点数取2个)
// 求连通块中节点的数量:并查集 for (int i = 0; i < n; i++) { p.push_back(i); // n个节点,每个节点最初是独立的,自己就是根节点 cnt.push_back(1); // cnt表示连通块(集合)中的节点个数 }
for (auto& e : edges) { int a = e[0], b = e[1]; a = find(a), b = find(b); if (a != b) { // 若 a 和 b 不在一个集合中,就计算2个集合中的节点数量之和,并 合并 cnt[b] += cnt[a]; // 集合的节点个数,只会看集合的根节点x对应的 cnt[find(x)]的数量 p[a] = b;// a的根节点的父节点是 b的根节点,b的根节点是新的集合的根节点 } }
LL res = (LL)n * (n - 1) / 2; // *处会爆int
// 遍历所有节点,找到每个集合的根节点 for (int i = 0; i < n; i++) { // 这里 p[i]已经是i的根节点了 // if (p[i] == i) // 节点i的根节点 == i, 即 i 为根节点 if (find(i) == i) // 也可以继续使用find(i)找i的根节点 res -= cnt[i] * (LL)(cnt[i] - 1) / 2; // * 处会爆int } return res; } };