P3367 【模板】并查集

定义

并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中,其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。

并查集

1.初始化
把每个点所在集合初始化为其自身。
通常来说,这个步骤在每次使用该数据结构时只需要执行一次,无论何种实现方式,时间复杂度均为O(N)。
void init(){
    for(int i=1;i<=n;i++) fa[i]=i;
}
2.查找
查找元素所在的集合,即根节点。(注意,fa数组表示的不一定是父亲,大部分是祖宗,要用递归的路径压缩实现)
int find(int x){
    if(fa[x]==x) return x;
    return find(fa[x]);
}
3.合并
将两个元素所在的集合合并为一个集合。
通常来说,合并之前,应先判断两个元素是否属于同一集合,这可用上面的“查找”操作实现。
void merge(int x,int y){
    x=find(x),y=find(y);
    if(x<y) fa[y]=x;
    else fa[x]=y;
}

4.最后的最后

好了,不说了,直接上题目

题目

题目描述

如题,现在有一个并查集,你需要完成合并和查询操作。

输入输出格式

输入格式:

第一行包含两个整数N、M,表示共有N个元素和M个操作。

接下来M行,每行包含三个整数Zi、Xi、Yi

当Zi=1时,将Xi与Yi所在的集合合并

当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N

输出格式:

如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N

输入输出样例

输入样例#1: 复制
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
输出样例#1: 复制
N
Y
N
Y

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据,N<=10,M<=20;

对于70%的数据,N<=100,M<=1000;

对于100%的数据,N<=10000,M<=200000。

分析

2019年夏天,NBA自由市场开始了,无数巨星离开了自己的队伍去其他队争冠去

这道题是一道普通的并查集,代码比较短,不是特别难,首先是要合并,然后再去判断是否在一个集合,总之来说可以看做NBA的球员在不在一个队

代码

#include<iostream>
using namespace std;
const int N=10100;
int fa[N],n,m;
void init(){
    for(int i=1;i<=n;i++) fa[i]=i;//每个球员都是老大
}
int find(int x){//寻找老大看是否是一队 
    if(fa[x]==x){
        return x;
    }
    return find(fa[x]);
}
void unite(int x,int y){//合并两名球员在一队 (例:合并伦纳德和乔治一队,选老大) 
    x=find(x),y=find(y);
    if(x<y) fa[y]=x;
    else fa[x]=y;
}
int main(){
    scanf("%d%d",&n,&m);
    init();//初始化 
    for(int i=1;i<=m;i++){
        int u,v,z;
        scanf("%d%d%d",&z,&u,&v);
        if(z==1) unite(u,v);//合并两名球员 
        if(z==2){
            if(find(u)==find(v)) printf("Y
");//如果在是一队的 (如果他们的老大相同,例:浓眉哥和考神的老大是詹姆斯DXX) 
            else printf("N
");//如果不是(例:哈登老大是威少【以前的】,而西帝老大是大帝) 
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/earth833/p/11206852.html