难点
- 这个题的难点就在于节点的删除
- 目前题解中都是使用虚拟的父节点,本代码也是如此所以将具体讲解不再赘述。
- 本代码的亮点在于使用了 带路径压缩的按秩合并的方法。
- 下面为c++代码实现。
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2e6+10;
int n, m;
struct note{
int par, rak, vis;
}tre[N];
int find(int x)
{
if(tre[x].par==x) return x;
else return tre[x].par=find(tre[x].par);
}
void init()
{
for(int i=0;i<n;i++)
{
tre[i].par=i+n;
tre[i].rak=0;
tre[i].vis=0;
}
for(int i=n; i <= (n<<1)+m; i++)
{
tre[i].par=i;
tre[i].rak=0;
tre[i].vis=0;
}
}
void merge(int x, int y)
{
x=find(x);
y=find(y);
if(x==y) return ;
if(tre[x].rak < tre[y].rak)
tre[x].par=tre[y].par;
else {
tre[y].par=tre[x].par;
if(tre[y].rak==tre[x].rak) tre[x].rak++;
}
}
int main()
{
int step=1, ans;
char op[2];
int x, y, del;
while(scanf("%d%d", &n, &m) && n+m!=0)
{
init();
int cnt = n<<1;
for(int i=1; i<=m; i++)
{
scanf("%s", op);
if(op[0]=='M'){
scanf("%d%d", &x,&y);
merge(x, y);
}else {
scanf("%d", &del);
tre[del].par=cnt++;
}
}
ans=0;
for(int i=0; i<n; i++)
{
int tmp=find(i);
if(tre[tmp].vis==0){
tre[tmp].vis=1;
ans++;
}
}
printf("Case #%d: %d\n", step++, ans);
}
return 0;
}