本题考查的是并查集的删除.
在删除结点的时候要注意这样的问题: 并查集的结构是一棵树,当把某一个结点删去(将其父结点置为自己)时,它的子结点的根就会丢失.因此,在删除某结点的时候,要确定它的所有子结点都已经并到根上了.
解决方法: 为每一个结点加一个虚根,这样每个结点都是叶子结点.插入结点时,把它们都并到虚根的集合中.删除结点时,只要把它的父结点置为一个无用的虚根
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; }