?所谓并查集就是可以画图理解
假如说我们想要构建一个树(也是图),要求1->2,2->4,1->3
在构另一个树,要求5->6,6->7,5->8
1是2的头结点,2是4的头结点,以此类推
下面要求去将5连接到1上,就是我下面要讲的,其实上面的子节点的连接也是如此的。
一共有 n 个数,编号是 1~n,最开始每个数各自在一个集合中。
现在要进行 m 个操作,操作共有两种:
第一行输入整数 n 和 m。
接下来 m 行,每行包含一个操作指令,指令为 M a b 或 Q a b 中的一种。
对于每个询问指令 Q a b,都要输出一个结果,如果 a 和 b 在同一集合内,则输出 Yes,否则输出 No。
每个结果占一行。
分析一下:
面对这种比较新的数据结构一般都是非常抽象的,但是一旦通过画图或者推理理解了,也就很容易记住了,首先我们将p[i]=i,为的是存储此树的头结点,接下来要进行连接的操作,就要通过find(),压缩一下路径。将子节点连接到p[b]=find(p[a])(a为子节点,b为父节点),下面都是这种操作。
然后这个题目他让判断是不是在一个集合就可以find(a)==find(b)来判断是不是头结点一样,因为最终find(a)返回的是头结点的值。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int p[N];
int find(int x){//返回x的祖宗节点+路径压缩
if(p[x]!=x)p[x]=find(p[x]);//只有祖宗节点才有p[x]=x
return p[x];
}
int n,m;
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)p[i]=i;
for(int i=1;i<=m;i++){
char op[2];//读字符串比读字符更省事
int a,b;
scanf("%s%d%d",op,&a,&b);
if(*op=='M')p[find(a)]=find(b);
else {
if(find(a)==find(b))printf("Yes\n");
else printf("No\n");
}
}
}
给定一个包含?n?个点(编号为?1~n)的无向图,初始时图中没有边。
现在要进行?m?个操作,操作共有三种:
C a b
,在点?a?和点?b?之间连一条边,a?和?b?可能相等;Q1 a b
,询问点?a?和点?b?是否在同一个连通块中,a?和?b?可能相等;Q2 a
,询问点?a?所在连通块中点的数量;第一行输入整数?n?和?m。
接下来?m?行,每行包含一个操作指令,指令为?C a b
,Q1 a b
?或?Q2 a
?中的一种。
对于每个询问指令?Q1 a b
,如果?a和?b在同一个连通块中,则输出?Yes
,否则输出?No
。
对于每个询问指令?Q2 a
,输出一个整数表示点?a 所在连通块中点的数量
每个结果占一行。
1≤n,m≤10^5
5 5
C 1 2
Q1 1 2
Q2 1
C 2 5
Q2 5
Yes
2
3
?这个题的求节点数,只用拿个数组将所有的子节点连接过程一一地加到父节点的si[b](b为父节点),最后输出的是si[find(a)](a为树中任意一个数)。这样我们就求到了树的节点数。
但是别忘记初始化为si[i]=1,不是si[i]=i
#include<bits/stdc++.h>
#define read(x) scanf("%d",&x)
using namespace std;
const int N = 1e5+5;
int n,m,a,b,fa[N], si[N];
string act;
void init() {//初始化
for (int i=1; i<=n; i++) {
fa[i] = i;
si[i] = 1;
}
}
int find(int x) {//查找父节点
if(fa[x]==x) return x;
else return fa[x] = find(fa[x]);
}
void merge(int a,int b) {//节点数加起来
int x = find(a);
int y = find(b);
fa[x] = y;
si[y] += si[x];
}
bool ask(int a,int b) {//询问是不是头结点一样
return find(a)==find(b);
}
int main() {
read(n),read(m);
init();
while(m--) {
cin>>act;
if(act=="C") {
read(a),read(b);
if(!ask(a,b)) merge(a,b);
} else if(act=="Q1") {
read(a),read(b);
ask(a,b) ? printf("Yes\n") : printf("No\n");
} else {
read(a);
printf("%d\n",si[find(a)]);
}
}
return 0;
}
以上就是并查集这一种数据结构的代码思路和方法了。