题目链接 :点击打开链接
题目大意:
n个点,可以进行4种操作
1.将u,v所在的集合合并
2.将u从其所在集合删除
3.查询u所在集合的大小
4.查询u v是否在同一集合。
解题思路:
很明显的并查集模板,但是有个问题就是删除操作,而且这里面的删除操作不会导致原有的集合发生变化,意思就是只有这个点被删除掉。不考虑类似于图中边相连的情况。
专门学习了一下点的删除,其实就是用一个额外的数组记录i当前真正对应的位置,可以称为虚根吧,当我们吧u删除掉的时候,我们令pos[u]=++cnt,这样的话原来的u不会影响我们的其他操作,新的u也可以正常进行其他的操作。
Ac代码:
#include<bits/stdc++.h>
#define real re
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
const int INF=1e9+7;
const int mod=1e9+7;
int n,m,cnt,par[maxn*10],real[maxn],num[maxn*10]; //num记录集合的大小
void init() //初始化
{
cnt=n;
for(int i=0;i<=n;i++) par[i]=i;
for(int i=0;i<=n;i++) real[i]=i;
for(int i=0;i<=n;i++) num[i]=1;
}
int find(int x)
{
if(par[x]==x) return x;
else return par[x]=find(par[x]);
}
int main()
{
int QAQ,kase=0;
scanf("%d",&QAQ);
while(QAQ--)
{
scanf("%d%d",&n,&m);
init();
printf("Case #%d:\n",++kase);
while(m--)
{
int flag,u,v;
scanf("%d",&flag);
if(flag==1) //一切操作都以real执行
{
scanf("%d%d",&u,&v);
int fx=find(real[u]),fy=find(real[v]);
if(fx!=fy) par[fx]=fy,num[fy]+=num[fx];
}
if(flag==2) //这里注意num-- 然后开出新的点
{
scanf("%d",&u);
num[find(real[u])]--;real[u]=++cnt;
par[real[u]]=real[u];num[real[u]]=1;
}
if(flag==3)
{
scanf("%d",&u);
printf("%d\n",num[find(real[u])]);
}
if(flag==4) //直接查询即可
{
scanf("%d%d",&u,&v);
int fx=find(real[u]),fy=find(real[v]);
if(fx==fy) printf("YES\n");
else printf("NO\n");
}
}
}
//system("pause");
}