算法模板:并合集

并合集

题目描述
一共有n个数,编号是1~n,最开始每个数各自在一个集合中。
现在要进行m个操作,操作共有两种:
“M a b”,将编号为a和b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
“Q a b”,询问编号为a和b的两个数是否在同一个集合中;

#include<iostream>

using namespace std;
const int N = 1e6 + 10;
int p[N];

```cpp
int find(int x)
{
    
    
    if(p[x] != x)p[x] = find(p[x]);
    return p[x];
}

int main(void)
{
int n,m;
cin>>n>>m;
for(int i = 1 ; i <= n ; i ++ )p[i] = i;

while(m--)
{
    char op[2];
    int a, b;
    scanf("%s%d%d" ,op,&a,&b);
    if(op[0] == 'M')
    {
        p[find(a)] =find(b);
    }
    else if(op[0] == 'Q')
    {
        if(find(a) == find(b))puts("Yes");
        else puts("No");
    }
}

}

**并合集**
一种快速对字符串以及二进制数组元素的管理方式,用树的形式进行存储;
**代码分析**
对于1~n这些数字,我们创建了一个数组p来记录他的祖先节点,运用下标与实际数字进行关联,例如p[i]记录的就是i的祖先节点,在程序一开始的时候,我们将每个节点的祖先设置为他自己,然后通过合并数组的操作实现树的建立;
*集合的合并*
树的根节点存储集合的信息,p数组的单元存储节点的祖先,将根节点的祖先修改为另一个集合就完成了就和的合并;

```cpp
int find(int x)
{
    if(p[x] != x)p[x] = find(p[x]);
    return p[x];
}

这一个操作就完成了寻找x的祖先根节点

猜你喜欢

转载自blog.csdn.net/ZMTH010123/article/details/114439563