数据结构--并查集

一、概述

1、定义:并查集是一种树型的数据结构

2、应用:用于处理不相交的集合的合并和查询。

二、操作及实现

1、查询:找到自己的老大

cpp 复制代码
int find(int x)
{
    while(f[x]!=x)//如果自己的老大不是自己说明老大另有其人
    {
        x=f[x];//接着往下找老大
    }
    return x;//找到了老大
}

2、合并:合并成一个团伙

cpp 复制代码
void join(int x,int y)
{
    int fx=find[x],fy=find[y];//找到两个人各自的老大
    if(fx!=fy)//如果两个人的老大不一样说明不是一个团伙
    {
        f[fx]=fy;//要合并成一个团伙,只能有一个老大,所以说其中一个老大要认另一个老大做新老大。
    }
}

3、路径压缩:(优化find函数)

如果树的深度过深,查询起来会相当耗时,所以说要减短树的深度。

可以将查询点x到根节点(也就是老大)的途径的点的父节点都设成为根节点,会大大降低查询的难度。

缺点是:只有当找到老大时,才能进行路径压缩,所以每个团体第一次的查询是没有什么优化的,之后才会生效。

cpp 复制代码
int find(int x)//路径压缩 
{
	if(f[x]==x)return x;//如果自己的老大是自己输出
	return f[x]=find(f[x]);//如果不是,继续找老大,并且把自己的父节点设为老大
}

三、模板和例题

1、模板

洛谷P3367

https://www.luogu.com.cn/problem/P3367#submithttps://www.luogu.com.cn/problem/P3367#submit

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int f[N],a,b,c;
int find(int k)
{
	//路径压缩 
	if(f[k]==k)return k;
	return f[k]=find(f[k]);
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		f[i]=i;//初始化老大为自己 
	}
	for(int i=1;i<=m;i++)
	{
		cin>>a>>b>>c;
		if(a==1)
		{
			f[find(b)]=find(c);//合并  c所在组赢了b所在组 
		}
		else
		{
			if(find(b)==find(c))//检查老大是否相同 
			{
				cout<<"Y"<<endl;
			}
			else
			{
				cout<<"N"<<endl;
			}
		}
	}
	return 0;
} 

2、acwing 837、连通块中点的数量

https://www.acwing.com/problem/content/839/

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,f[N],cnt[N];
int find(int x)//不能用路径压缩因为那样的话就没办法统计连通快的数量了
{
    if (f[x] != x) f[x] = find(f[x]);
    return f[x];
}
void join(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
    {
        f[fx]=fy;
    }
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
        cnt[i]=1;
    }
    while(m--)
    {
        string flag;
        cin>>flag;
        int a,b;
        if(flag=="C")
        {
            cin>>a>>b;
            if(find(a)==find(b))continue;
            cnt[find(b)]+=cnt[find(a)];//先加连通块数量,否则先操作集合的话会导致重叠。而且要给新老大加,不能加错
            join(a,b);
        }
        else if(flag=="Q1")
        {
            cin>>a>>b;
            if(find(a)==find(b))
            {
                cout<<"Yes"<<endl;
            }
            else
            {
                cout<<"No"<<endl;
            }
        }
        else
        {
            cin>>a;
            cout<<cnt[find(a)]<<endl;
        }
    }
    return 0;
}

3、acwing 240食物链

cpp 复制代码
//把食物环拆成食物链,用某节点到根节点的距离%3的余数来表示各节点之间的关系。
/*
余1:吃根节点
余2:被根节点吃
余0:同类
*/
#include<bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int f[N],d[N];
int n,m;
int find(int x)
{
    if(f[x]!=x)//自己不是根节点
    {
        int t=find(f[x]);//先压缩路径使除x外的所有上级都指向根节点并记录根节点是谁
        d[x]+=d[f[x]];//到根节点的距离更新为x到其父节点的距离+父节点到根节点的距离
        f[x]=t;//再让x指向根节点
    }
    return f[x];
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        f[i]=i;
    }
    int res=0;
    while(m--)
    {
        int t,x,y;
        cin>>t>>x>>y;
        if(x>n||y>n)
        {
            res++;
            continue;
        }
        int fx=find(x),fy=find(y);
        if(t==1)//同类
        {
            //在同一集合中
            if(fx==fy&&(d[x]-d[y])%3)res++;//两者%3不相等,说明不是同一类,谎话++
            else if(fx!=fy)//不在同一集合中,先到者为真
            {
                f[fx]=fy;//合并集合,让其中一个老大认另一个人做老大
                d[fx]=d[y]-d[x];//因为同类,所以(d[x]+d[fx]-d[y])%3==0
            }
        }
        //同上
        else
        {
            if(fx==fy&&(d[x]-d[y]-1)%3)res++;
            else if(fx!=fy)
            {
                f[fx]=fy;
                d[fx]=d[y]+1-d[x];
            }
        }
    }
    cout<<res<<endl;
    return 0;
}
相关推荐
XLYcmy11 分钟前
TarGuessIRefined密码生成器详细分析
开发语言·数据结构·python·网络安全·数据安全·源代码·口令安全
KingRumn18 分钟前
DBUS源码剖析之DBusMessage数据结构
linux·服务器·数据结构
youngee1143 分钟前
hot100-61电话号码的字母组合
java·数据结构·leetcode
jackyrongvip1 小时前
10个动画介绍递归(用Gemin3生成)
数据结构·递归·gemin3
一条大祥脚2 小时前
26.1.1
数据结构·算法
chushiyunen4 小时前
快慢双指针算法笔记
数据结构·笔记·算法
@小码农5 小时前
202512 电子学会 Scratch图形化编程等级考试三级真题(附答案)
服务器·开发语言·数据结构·数据库·算法
报错小能手6 小时前
数据结构 字典树
开发语言·数据结构
XLYcmy6 小时前
高级密码生成器程序详解:专门设计用于生成基于用户个人信息的密码猜测组合
开发语言·数据结构·python·网络安全·数据安全·源代码·口令安全
AI科技星6 小时前
时空的固有脉动:波动方程 ∇²L = (1/c²) ∂²L/∂t² 的第一性原理推导、诠释与验证
数据结构·人工智能·算法·机器学习·重构