求連通塊(並查集實現)
阿新 • • 發佈:2018-12-22
連通塊可以理解為無向圖中有幾個連通的點集,那麼這個過程與並查集的原理就極其相似了,將點集看作並查集的祖先和他的後代們,相互連通的點就放在同一祖先下,這樣只需要查詢共有幾個祖先即可。
當我們加入一個點時,先假設又加入一個單獨的連通塊,然後再掃一下與它相連的點如果在圖中但是與它不在一個連通塊中,那麼就將其合併,連通塊個數減一。
AC程式碼如下:
#include<iostream> #include<cstdio> #include<vector> using namespace std; const int MAX_N = 400005; const int MAX_M = 200005; vector <int> vec[MAX_N]; int f[MAX_N],flag[MAX_N], num[MAX_N],ans[MAX_N]; int tot = 0; int find(int x){ if(x != f[x]) f[x] = find(f[x]); return f[x]; } void connect(int x){ tot++; int sz = vec[x].size(); for(int i = 0; i < sz; i++){ if(flag[vec[x][i]]){ int fa = find(x); int fb = find(vec[x][i]); if(fa != fb){ tot--; f[fb] = fa; } } } flag[x] = 1; } int main(){ int n, m, k; cin >> n >> m; for(int i = 0; i <= n; i++){ f[i] = i; flag[i] = 1; } for(int i = 0; i < m; i++){ int a, b; scanf("%d%d",&a,&b); vec[a].push_back(b); vec[b].push_back(a); } cin >> k; for(int i = 1; i <= k; i++){ scanf("%d",&num[i]); flag[num[i]] = 0; } for(int i = 0;i < n; i++){ if(flag[i]) connect(i); } ans[k+1] = tot; for(int i = k; i >= 1; i--){ connect(num[i]); ans[i] = tot; } for(int i = 1;i <= k + 1; i++){ printf("%d\n",ans[i]); } return 0; }