#include<bits/stdc++.h>
using namespace std;
// 并查集数组,fa[x]表示x的父节点
int fa[1000086];
int n, m, z, x, y;
// 并查集核心:查找函数(带路径压缩)
// 作用:找到元素x的祖先
int find(int x) {
// 如果自己就是祖先,直接返回
if (fa[x] == x)
return x;
// 递归查找父节点,同时路径压缩(让x直接指向祖先,下次查找更快)
else
return fa[x] = find(fa[x]);
}
int main() {
// 输入:n个元素,m次操作
cin >> n >> m;
// 初始化并查集
// 最开始每个元素的父节点都是自己,自己是一个独立集合
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
// 执行m次操作
while (m--) {
// 输入
cin >> z >> x >> y;
// 分别找到x和y的祖先
int fx = find(x);
int fy = find(y);
// 操作2:查询 x 和 y 是否在同一个集合里
if (z == 2) {
// 判断输出
if (fx == fy)
cout << "Y\n";
else
cout << "N\n";
}
// 操作1:合并 x 和 y 所在的集合
else if (z == 1) {
// 让其中的祖先等于另一个
fa[fx] = fy;
}
}
return 0;
}
P1551 亲戚
#include<bits/stdc++.h>
using namespace std;
int pa[10086];
// 查找函数:带路径压缩,找到x所在集合的祖先
int find(int x){
if(pa[x]!=x){
pa[x] = find(pa[x]);
}
return pa[x];
}
int main(){
int n,m,p;
cin >> n >> m >> p;
// 并查集初始化
for(int i=1;i<=n;i++){
pa[i] = i;
}
// 循环处理m组亲戚关系,合并两个集合
for(int i=0;i<m;i++){
int a,b;
cin >> a >> b;
// 分别找到两个人的祖先
a = find(a);
b = find(b);
// 如果两个人不在同一个集合,合并
if(a != b){
pa[b] = a;
}
}
for(int i=0;i<p;i++){
int a,b;
cin >> a >> b;
if(find(a) == find(b)){
cout << "Yes" << endl;
}else{
cout << "No" << endl;
}
}
return 0;
}
P3366 【模板】最小生成树
#include<bits/stdc++.h>
using namespace std;
int p[5086];
// 边的结构体:存储一条边的 起点u、终点v、权值w
struct Edge{
int u, v, w;
}edge[200086]; // 存储所有边
// 并查集查找函数(带路径压缩)
// 作用:找到 x 所在集合的根节点
int find(int x){
// 如果 x 不是根节点,就递归找根,同时路径压缩
if(p[x] != x){
p[x] = find(p[x]);
}
return p[x]; // 返回根节点
}
//排序比较函数:让边按权值从小到大排序
bool cmp(Edge a, Edge b){
return a.w < b.w;
}
int main(){
int n, m;
// n:点数 m:边数
cin >> n >> m;
//初始化并查集
for(int i = 1; i <= n; i++){
p[i] = i;
}
//输入 m 条边的信息
for(int i = 0; i < m; i++){
cin >> edge[i].u >> edge[i].v >> edge[i].w;
}
//核心:把所有边按权值从小到大排序(Kruskal 关键步骤)
sort(edge, edge + m, cmp);
int sum = 0; // 最小生成树的总权值和
int cnt = 0; // 已经选了多少条边
//从小到大遍历每条边,尝试加入最小生成树
for(int i = 0; i < m; i++){
// 取出当前边的起点、终点、权值
int u = edge[i].u;
int v = edge[i].v;
int w = edge[i].w;
// 查找两个点的根节点
int a = find(u);
int b = find(v);
// 如果两个点不在同一个集合(不会形成环)
if(a != b){
p[a] = b; // 合并两个集合
sum += w; // 把这条边的权值加入总和
cnt++; // 选中的边数 +1
// 最小生成树只需要 n-1 条边,够了就提前退出
if(cnt == n - 1){
break;
}
}
}
// 判断是否构成最小生成树
if(cnt == n - 1){
cout << sum << endl;
}
else{
cout << "orz" << endl;
}
return 0;
}