题面

分析
这题是真的模板呢。
不会并查集的读者可以看这里: 并查集之云宗的分分合合。
刚开始,每个人都是自己所在集合的根节点。(每个人都是独立的集合中唯一的元素)
void start()
{
for(int i=1;i<=n;i++)fa[i]=i;
}
fa[ i ] 存储结点 i 的父节点。
合并和查询操作都需要查找一个集合的根,下面是查根函数。
int root(int x)
{
if(fa[x]==x)return x;
else return fa[x]=root(fa[x]);
}
然后就是合并操作啦。
只需要 将集合A的根节点 设为集合B的根节点的子节点 ,就合并完了。
void merge(int x,int y)
{
fa[root(x)]=root(y);
}
最后是查询操作,同样,只需要看两者的根节点是否相同即可。
bool check(int x,int y)
{
return root(x)==root(y);
}
完整代码
#include <bits/stdc++.h>
using namespace std;
int n,m,z,x,y;
int fa[10001];
void start()
{
for(int i=1;i<=n;i++)fa[i]=i;
}
int root(int x)
{
if(fa[x]==x)return x;
else return fa[x]=root(fa[x]);
}
bool check(int x,int y)
{
return root(x)==root(y);
}
void merge(int x,int y)
{
fa[root(x)]=root(y);
}
int main ()
{
cin>>n>>m;
start();
for(int i=1;i<=m;i++)
{
cin>>z>>x>>y;
if(z==2)//查
{
if(check(x,y))cout<<"Y"<<endl;
else cout<<"N"<<endl;
}
else//并
{
merge(x,y);
}
}
return 0;
}
我们接着考虑进一步优化。
优化并查集有两种办法,路径压缩和按秩合并,这里介绍一下按秩合并的写法。
我们有大小为 a 的集合 A 和大小为 b 的集合 B (a < b),现要将它们合并。
我们有两种方案,把 A 并到 B ,或者把 B 并到 A 。
很明显,把 A 并到 B 更优。
B的祖宗:@A的祖宗 我们族人多,还是你们来吧。
A的祖宗:好的。
所以我们得出,要将大小小的集合并到大小大的集合中。
下面是优化写法。
#include <bits/stdc++.h>
using namespace std;
int n,m,z,x,y;
int fa[10001],sz[10001];
void start()
{
for(int i=1;i<=n;i++)
{
fa[i]=i;
sz[i]=1;
}
}
int root(int x)
{
if(fa[x]==x)return x;
else return fa[x]=root(fa[x]);
}
bool check(int x,int y)
{
return root(x)==root(y);
}
void merge(int x,int y)
{
x=root(x),y=root(y);
if(x==y) return;
if(sz[x]>sz[y])swap(x,y);
sz[y]+=sz[x];
fa[x]=y;
}
int main ()
{
cin>>n>>m;
start();
for(int i=1;i<=m;i++)
{
cin>>z>>x>>y;
if(z==2)//查
{
if(check(x,y))cout<<"Y"<<endl;
else cout<<"N"<<endl;
}
else//并
{
merge(x,y);
}
}
return 0;
}
以上就是这道模板题的题解啦。
推荐继续尝试:洛谷 P1551 亲戚
题解通道:[建设中]
本文详细介绍了并查集的基础概念和实现,包括初始化、查找根节点、合并与查询操作。并展示了两种并查集的优化方法:路径压缩和按秩合并。通过示例代码解释了按秩合并的优化策略,提高了集合合并的效率。
856

被折叠的 条评论
为什么被折叠?



