本題考查的是並查集的刪除.
在刪除結點的時候要注意這樣的問題: 並查集的結構是一棵樹,當把某一個結點刪去(將其父結點置為自己)時,它的子結點的根就會丟失.因此,在刪除某結點的時候,要確定它的所有子結點都已經併到根上了.
解決方案: 為每一個結點加一個虛根,這樣每個結點都是葉子結點.插入結點時,把它們都併到虛根的集合中.刪除結點時,只要把它的父結點置為一個無用的虛根
http://blog.csdn.net/a181551981/article/details/6286007
#include <iostream> #include <string> using namespace std; int n,m,a,b,cnt,father[2000000],s[1000041],ans; int find(int x);void merge(int x,int y);//固定根節點,n+1~n+n作為根節點,而1~n作為虛擬根節點(指向n+1~n+n),之後在增添n+n~n+n+m作為備用節點 //刪除時直接修改1~n指向的節點到n+n後的節點 int main(){ int Case = 1, n, m, i, a, b, ans; char ch;while(cin>>n>>m && (n||m)){ for(i = 0; i < n; i++)father[i] = i + n;for(i = n; i < n*2+m;i++)father[i] = i;cnt = 2 * n; ans = 0;memset(s, 0, sizeof(s));while(m--){cin>>ch;if(ch == 'M'){cin>>a>>b;merge(a, b);}else{cin>>a;father[a] = cnt++;}}for(i = 0; i < n; i++){int temp = find(i);if(s[temp] == 0){ans++;s[temp] = 1;}}cout<<"Case #"<<Case<<": "<<ans<<endl;Case++;} return 0; } int find(int x) { int temp = x,sum = 0,ans; while(temp != father[temp]) { temp = father[temp]; }ans = temp; while(x != ans) { temp = father[x]; father[x] = ans; x = temp; } return ans;}void merge(int a,int b){int x = find(a);int y = find(b);if(x < y)father[y] = x;else if(x > y)father[x] = y;}