P3367 【模板】并查集
题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。
输入格式
第一行包含两个整数N
,M
,表示共有N
个元素和M
个操作。接下来M
行,每行包含三个整数Zi
,Xi
,Yi
。
-
当
Zi=1
时,将Xi
与Yi
所在的集合合并。 -
当
Zi=2
时,输出Xi
与Yi
是否在同一集合内,是的输出Y
;否则输出N
。
输出格式
对于每一个Zi=2
的操作,都有一行输出,每行包含一个大写字母,为Y
或者N
。
输入输出样例
输入 | 输出 |
---|---|
4 7 2 1 2 1 1 2 2 1 2 1 3 4 2 1 4 1 2 3 2 1 4 | N Y N Y |
说明/提示
对于30%
的数据,N≤10
,M≤20
。
对于70%
的数据,N≤100
,M≤1E3
。
对于100%
的数据,1≤N≤1E4
,1≤M≤2×1E5
。
代码
并查集没什么好讲的,解释都在注释里了
//c++ --std=c++99
#include <cstdio>
struct ufsets_elem{ //并查集元素
ufsets_elem *root;
ufsets_elem(){
root = this;
}
ufsets_elem *find(){
return root == this ? root : root = root->find(); //路径压缩
}
};
struct ufsets{ //并查集
protected:
int ufsets_num; //独立集合数量
ufsets_elem *ufsets_base; //并查集数组
public:
explicit ufsets(const int &n){
ufsets_base = new ufsets_elem[n + 1]();
ufsets_num = n;
}
bool catenate(const int &a, const int &b){ //合并a,b集合,返回false则说明两元素已是同一集合
if (ufsets_base[a].find() != ufsets_base[b].find()){ //若a,b不在同一集合则合并b至a
--ufsets_num;
ufsets_base[b].root->root = ufsets_base[a].root;
return true;
}
return false;
}
bool relative(const int &a, const int &b){ //查询是否在同一个集合中,是则返回true
return ufsets_base[a].find() == ufsets_base[b].find();
};
int size(){//独立集合数量
return ufsets_num;
}
~ufsets(){
delete[] ufsets_base;
}
};
int main(){
int n, m;
int tmp1, tmp2, tmp3;
scanf("%d%d", &n, &m);
ufsets u(n);
for (int i = 1; i <= m; ++i){
scanf("%d%d%d", &tmp1, &tmp2, &tmp3);
switch (tmp1){
case 1:
u.catenate(tmp2, tmp3); //将tmp3所在集加入到tmp2中
break;
case 2:
printf("%c\n", u.relative(tmp2, tmp3) ? 'Y' : 'N');
break;
}
}
return 0;
}
//java
import java.util.*;
import java.math.*;
class ufsets_elem{ //并查集元素
public ufsets_elem root;
ufsets_elem(){
root = this;
}
ufsets_elem find(){
return root == this ? root : (root = root.find()); //路径压缩
}
};
class ufsets{ //并查集,依赖于class ufsets_elem
int ufsets_num; //独立集合数量
ufsets_elem[] ufsets_base; //并查集数组
ufsets(final int n){
ufsets_base = new ufsets_elem[n + 1];
for(int i=1;i<=n;i++)//ufsets_base[0]用不到
ufsets_base[i]=new ufsets_elem();
ufsets_num = n;
}
boolean catenate(final int a, final int b){ //合并a,b集合,返回false则说明两元素已是同一集合
if (ufsets_base[a].find() != ufsets_base[b].find()){ //若a,b不在同一集合则合并b至a
--ufsets_num;
ufsets_base[b].root.root = ufsets_base[a].root;//b更改的是其父节点的<root>
return true;
}
return false;
}
boolean relative(final int a, final int b){ //查询是否在同一个集合中,是则返回true
return ufsets_base[a].find() == ufsets_base[b].find();
};
int size(){//独立集合数量
return ufsets_num;
}
};
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(), m=sc.nextInt();
int tmp1, tmp2, tmp3;
ufsets u=new ufsets(n);
for (int i = 1; i <= m; ++i){
tmp1=sc.nextInt();tmp2=sc.nextInt();tmp3=sc.nextInt();
switch (tmp1){
case 1:
u.catenate(tmp2, tmp3); //将tmp3所在集加入到tmp2中
break;
case 2:
System.out.print((u.relative(tmp2, tmp3) ? 'Y' : 'N')+"\n");
break;
}
}
}
}
同一套代码java慢好多,枯了