题意一共n棵树,有4种操作。操作1:把两棵树所在的森林合并起来。操作2:把一棵树从它所在的森林中分离出来。操作3:询问一棵树所在森林的树的数量。操作4:询问两棵树是否在同一片森林中。
思路:都是对于集合的操作,所以可以用并查集解决。对于分离操作,则是相当于把原来森林的树的数量-1,然后新建一棵树,而不是把原有的树覆盖掉,因为有可能还存在该树的孩子没有通过路径压缩直接指向整个集合的父节点。。。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<string>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define PI acos(-1)
#define INF 0x3f3f3f3f
#define NUM 100100
const int p = 1e9+7;
int T,n,q;
int _index[NUM<<1],_father[NUM<<1];
int snum[NUM<<1];
int getfather(int x)
{
if(_father[x]==x)
return _father[x];
return _father[x]=getfather(_father[x]);
}
void Merge(int x,int y)//合并
{
_father[x]=getfather(_father[x]);
_father[y]=getfather(_father[y]);
if(_father[x]==_father[y])return ;
snum[_father[y]]+=snum[_father[x]];
snum[_father[x]]=0;
_father[_father[x]]=_father[y];
}
void Separate(int x)//分离
{
int y=_index[x];
_father[y]=getfather(_father[y]);
if(snum[_father[y]]==1)
return ;
++n;
--snum[_father[y]];
_index[x]=n;
_father[n]=n;
snum[n]=1;
}
void QuerySize(int x)//询问数量
{
_father[x]=getfather(_father[x]);
printf("%d\n",snum[_father[x]]);
}
void Query(int x,int y)//询问是否在同一片森林
{
_father[x]=getfather(_father[x]);
_father[y]=getfather(_father[y]);
if(_father[x]==_father[y])
printf("YES\n");
else
printf("NO\n");
}
int main()
{
int op;
int x,y,t=0;
scanf("%d",&T);
while(T--)
{
++t;
printf("Case #%d:\n",t);
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i)
{
_father[i]=_index[i]=i;
snum[i]=1;
}
while(q--)
{
scanf("%d",&op);
switch(op)
{
case 1:scanf("%d%d",&x,&y);Merge(_index[x],_index[y]);break;
case 2:scanf("%d",&x);Separate(x);break;
case 3:scanf("%d",&x);QuerySize(_index[x]);break;
case 4:scanf("%d%d",&x,&y);Query(_index[x],_index[y]);break;
default :break;
}
}
}
}