题意:第一行输入 N(0 < N <= 10000 )和 M(0 < M <= 100000 )分别代表节点数和边数,接下来 M 行每行有两个数 u 和 v(0 <= u, v < N)代表 u 和 v 两点间有边连接。输出 M 行,输出删掉前 i 个边时的连通块。
解法:用并查集从后往前加边。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> using namespace std; const int N = 10010; const int M = 100010; int n,m; int ans[M], fa[N]; struct node{ int u,v; }edge[M]; //找最终祖先 int findfa(int x){ if(fa[x] != x) fa[x] = findfa(fa[x]); return fa[x]; } int main() { freopen("a.txt", "r", stdin); while(scanf("%d %d", &n, &m) != EOF){ memset(ans, 0, sizeof(ans)); memset(edge, 0, sizeof(edge)); //预处理 for(int i = 0; i < n; i++) fa[i] = i; for(int i = 0; i < m; i++) scanf("%d %d", &edge[i].u, &edge[i].v); int sum = n; for(int i = m-1; i >= 0; i--){ ans[i] = sum; //合并 int xx = findfa(edge[i].u); int yy = findfa(edge[i].v); if(xx != yy){ sum--; fa[xx] = yy; } } for(int i = 0; i < m; i++) printf("%dn", ans[i]); } return 0; }
并查集分为三部分:预处理、找祖先、合并。
在 findfa 函数中使用了路径压缩:findfa 函数中的 return 可以在回溯时压缩路径,也就是说当我们从一条链上的最后一个节点往上找到祖先后,这条链上所有的点 i 的 fa[i]都被更新成了这条链上的祖先。