数据结构(1)并查集

news2024/11/19 16:25:29

(4条消息) 第五课、Trie树、并查集、堆和堆排序_yan__kai_的博客-CSDN博客

活动 - AcWing

 并查集作用:一群元素将可以归类到一个代表元素上。可以维护元素到根节点的距离。可以维护每个并查集的大小。

基本操作回顾基础课,特别是“食物链”那道题

目录

例题

1.格子游戏

2.搭配购买(并查集+01背包)

3.程序自动分析(离散化)

4.银河英雄传说(维护距离)

​编辑 ​编辑

5.奇偶分析

带边权的并查集

带扩展域的并查集


 

例题

1.格子游戏

 画一条边可以将两个点连通,当出现封圈时,会将两个已经连通的点再连通。因此并查集处理连通块即可。

tips:把二维坐标压缩成一维坐标方便使用并查集。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=40010;

int n,m;
int p[N];

int get(int x,int y)
{
    return x*n+y;
}

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

int main()
{
    cin>>n>>m;
    for(int i=0;i<=n*n;i++) p[i]=i;

    int t=-1;

    for(int i=1;i<=m;i++)
    {
        int a,b;
        char d;
        cin>>a>>b>>d;
        a--,b--;
        int x,y;
        if(d=='D')
            x=a+1,y=b;
        else 
            x=a,y=b+1;
        int p1=get(a,b),p2=get(x,y);
        if(find(p1)==find(p2))
        {
            t=i;
            break;
        }
        p[find(p1)]=p[find(p2)];
    }

    if(t==-1)
        puts("draw");
    else 
        cout<<t;
    return 0;
}

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/5133179/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.搭配购买(并查集+01背包)

 将捆绑购买的云朵加入一个并查集,并查集需要维护云朵的价值和代价,与维护并查集的大小类似。注意不要加错了。

并查集处理完之后,做01背包即可。

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N =10010;

int f[N];
int n,m,vol;
int p[N];
int v[N],w[N];

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

int main()
{
    cin>>n>>m>>vol;
    for(int i=1;i<=n;i++)
        cin>>v[i]>>w[i];

    for(int i=1;i<=n;i++) p[i]=i;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        int pa=find(a),pb=find(b);
        if(pa!=pb)
        {
            v[pb]+=v[pa];
            w[pb]+=w[pa];
            p[pa]=pb;
        }
    }

    for(int i=1;i<=n;i++)
    {
        if(p[i]==i)
            for(int j=vol;j>=v[i];j--)
                f[j]=max(f[j],f[j-v[i]]+w[i]);
    }
    cout<<f[vol];
    return 0;
}

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/5133239/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

3.程序自动分析(离散化)

 如果相等,就合并。如果不相等,发现我们并不能做出什么动作,只能说明这两个数不在一个集合,但是不好在之后的判断中限定。

因此先处理所有相等条件,再判断约束条件即可。

发现i,j范围1e9,直接开数组空间爆了,所以需要离散化。离散化不需要维持数字的顺序,所以不需要排序判重二分,直接开一个hash表即可。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<unordered_map>
using namespace std;

const int N =2e5+10;

int p[N];
int n,m;
unordered_map<int,int> S;

struct Query{
    int x,y,e;
}query[N];


int get(int x)
{
    if(S.count(x)==0) S[x]=++n;
    return S[x];
}
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}

int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        cin>>m;
        S.clear();
        n=0;
        for(int i=0;i<m;i++)
        {
            int x,y,e;
            scanf("%d%d%d",&x,&y,&e);
            query[i]={get(x),get(y),e};
        }

        for(int i=1;i<=n;i++)
            p[i]=i;


        for(int i=0;i<m;i++)
        {
            if(query[i].e==1)
            {
                int pa=find(query[i].x),pb=find(query[i].y);
                p[pa]=pb;
            }
        }


        bool has_conflict=false;
        for(int i=0;i<m;i++)
        {
            if(query[i].e==0)
            {
                int pa=find(query[i].x),pb=find(query[i].y);
                if(pa==pb)
                {
                    has_conflict=true;
                    break;
                }
            }
        }
        if(has_conflict) puts("NO");
        else puts("YES");

    }
    return 0;
}

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/5133509/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

4.银河英雄传说(维护距离)

 

 看要求的两个操作:接在同一列,这个用并查集维护即可

判断间隔了多少艘战舰,那么我们需要维护节点到根节点的距离,把根节点作为排头即可。在合并过程中也需要思考怎么更新合并进来的结点的距离。

并查集路径压缩过程维护到根节点距离:路径压缩是让x一步指向根节点,则距离即x到原根节点的dist加上压缩之后,原根节点到新根节点的距离

int find(int x)
{
    if(p[x]!=x)
    {
        int root=find(p[x]);
        d[x]+=d[p[x]];
        p[x]=root;
    }
    return p[x];
}

合并过程更新距离:把新一列接在队尾,等价于直接把新一列接到根节点,但是新一列的根节点要向接收列的根节点连一条size[接收列]长度的边即可。那么路径压缩之后,新一列的所有节点到根节点的长度都会加size,满足条件。

答案为max(|d[a]-d[b]|-1,0)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

const int N =30010;

int m;
int p[N],s[N],d[N];

int find(int x)
{
    if(p[x]!=x)
    {
        int root=find(p[x]);
        d[x]+=d[p[x]];
        p[x]=root;
    }
    return p[x];
}

int main()
{
    cin>>m;
    for(int i=1;i<N;i++)
    {
        p[i]=i;
        s[i]=1;
    }

    while(m--)
    {
        char op[2];
        int a,b;
        scanf("%s%d%d",op,&a,&b);

        if(op[0]=='M')
        {
            int pa=find(a),pb=find(b);
            if(pa!=pb)
            {
                d[pa]=s[pb];
                s[pb]+=s[pa];
                p[pa]=pb;                
            }
        }
        else
        {
            int pa=find(a),pb=find(b);
            if(pa!=pb)
                puts("-1");
            else
            {
                cout<<max(abs(d[a]-d[b])-1,0)<<endl;
            }
        }
    }
    return  0;
}

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/5133756/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

5.奇偶分析

求一段区间的数据,我们可以考虑用前缀和数组能否挖掘出某些性质。

AcWing 239. 奇偶游戏 - AcWing题解作者Bug-Free

发现与sum数组的奇偶性有关,并且是等价关系。 

 接着分析判断情况。

带边权的并查集

和食物链那道题相似。如果给出两点的相关关系,则并入一个并查集,维护到根节点的距离d,为偶数则同类,奇数则不同类,模2之后只有0和1。则可以由距离推出任意两点的关系。

在合并时,根据根节点同不同类判断。

分为两种情况:之前没提到过即px!=py,,和之前提到过px==py。

如果提到过,则判断是否符合要求,即x到根节点的距离或上y到根节点的距离求异或值,则或之后的值为t则不矛盾。

如果没提到过,则合并,px到py的距离d需要满足:

如果是x,y是奇偶性相同,则dx+d+dy==0  即d=-dx-dy,d=dx^dy

如果不同,d==-dx-dy-1  d=dx^dy^1

统一一下就是dx^dy^t

综上:
如果px不等于py,合并,更新d(px)=dx^dy^t

如果等于,判断dx^dy==t

由数据范围可知,同样需要离散化。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<unordered_map>
using namespace std;

const int N =20010;

int n,m;
int p[N],d[N];
unordered_map<int,int> S;

int get(int x)
{
    if(S.count(x)==0) S[x]=++n;
    return S[x];
}

int find(int x)
{
    if(p[x]!=x)
    {
        int root=find(p[x]);
        d[x]+=d[p[x]];
        p[x]=root;
    }
    return p[x];
}

int main()
{
    cin>>n>>m;
    n=0;
    for(int i=0;i<N;i++) p[i]=i;
    int res=m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        string type;
        cin>>a>>b>>type;
        a=get(a-1),b=get(b);
        int t=0;
        if (type == "odd") t = 1;

        int pa=find(a),pb=find(b);
        if(pa==pb)
        {
            if(((d[a] + d[b]) % 2 + 2) % 2 != t)
            {
                res=i;
                break;
            }
        }
        else
        {
            p[pa]=pb;
            d[pa]=d[a]^d[b]^t;
        }
    }
    cout<<res;
    return 0;
}


作者:yankai
链接:https://www.acwing.com/activity/content/code/content/5134536/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

带扩展域的并查集

原数据有1~n,每个点有奇偶两种情况,我们用i+n表示这个点的另一种情况。

若没合并过:

如果给定x,y不同类,则说明x+n和y同类,x和y+n同类,x+n和y+n不同类。则合并同类情况。

如果给定x,y同类,则x+n和y+n同类,其他不同类。

如果合并了:

如果给定x y不同类,则判断x和y是否合并或者x+n和y+n是否合并,如果已合并,则矛盾。如果未合并,则合并x+n和y,y+n和x

如果给定同类,则判断x+n和y或者y+n和x是否合并。如果和并则矛盾。否则合并x和y ,x+n和y+n。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<unordered_map>
using namespace std;

const int N =20010,base = N / 2;

int n,m;
int p[N],d[N];
unordered_map<int,int> S;

int get(int x)
{
    if(S.count(x)==0) S[x]=++n;
    return S[x];
}

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

int main()
{
    cin>>n>>m;
    n=0;
    for(int i=0;i<N;i++) p[i]=i;
    int res=m;
    for(int i=0;i<m;i++)
    {
        int a,b;
        string type;
        cin>>a>>b>>type;
        a=get(a-1),b=get(b);

        if (type == "even")
        {
            if(find(a+base)==find(b))
            {
                res=i;
                break;
            }
            p[find(a)]=find(b);
            p[find(a+base)]=find(b+base);

        }
        else
        {
            if(find(a)==find(b))
            {
                res=i;
                break;
            }
            p[find(a+base)]=find(b);
            p[find(a)]=find(b+base);
        }
    }
    cout<<res;
    return 0;
}

作者:yankai
链接:https://www.acwing.com/activity/content/code/content/5134536/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/157078.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Django项目开发】部门管理模块的开发(八)

文章目录一、模型类设计二、视图设计1.都有哪些接口三、序列化器类设计四.分页操作1.utils工具中定义pagination.py2.视图类中使用五.路由配置一、模型类设计 一个部门下面可能会有很多子部门&#xff0c;一个子部门上面可能会有父部门&#xff1b;即部门内部之间进行关联&…

国科大模式识别与机器学习2022年期末总结

我根据本学期老师说的考试重点和我自身的情况总结的&#xff0c;希望能帮助到你&#xff0c;如有错误欢迎指正 目录第三章 判别函数Fisher线性判别感知机算法第四章 特征选择和提取K-L变换第五章 统计学习学习基础损失函数风险正则化过拟合欠拟合泛化误差第六章 有监督学习有监…

【jQuery】常用API——jQuery内容文本值

要针对元素的内容还有表单的值操作。 普通元素内容 html()&#xff08;相当于原生 inner HTML) html(); // 获取元素的内容html(内容); // 设置元素的内容<script src"../jquery.min.js"></script> </head><body><div><span>我是…

118页4万字智慧检务大数据平台解决方案

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料领取见文末&#xff0c;部分资料内容&#xff1a; 目录 第1章 前言 1.1、 政策背…

docker-compose keep-alive mysql8 互为主从

一、准备2台物理机器master-1、master-2&#xff0c;目标虚拟VIP。   VIP:192.168.1.139   master-1:192.168.1.17   master-2:192.168.1.20    二、然后分别在2台物理机器master-1、master-2上使用docker-compose安装mysql8&#xff0c;并配置互为主从。 1&#xff09…

优先级队列、仿函数和反向迭代器

文章目录优先级队列priority_queue的模拟实现框架无参的构造(默认构造)迭代器区间构造向上调整向下调整插入删除取堆顶的数据求数据个数验满初识仿函数模拟实现仿函数更改后的向上调整仿函数更改后的向下调整反向迭代器具体实现优先级队列 1.优先队列是一种容器适配器&#xf…

微信转账api(企业付款)

企业付款介绍 提供企业向用户付款的功能&#xff0c;支持企业通过API接口付款&#xff0c;或通过微信支付商户平台网页功能操作付款。 1. 充值 登录微信支付商户平台&#xff0c;通过网页充值功能充值&#xff08;商户平台-资金管理-现金管理-充值&#xff09;。 温馨提示&a…

BreederDAO x DigiCult AMA——要点总结

问&#xff1a;为什么 BreederDAO 决定花费 200ETH 用于购买 Mythic DigiDaigaku Genesis — Ifrit&#xff1f; 答&#xff1a;除了投资之外&#xff0c;这也是为了确保这个领域中有更多的可触达性&#xff0c;尤其是随着我们 DigiDaigaku 市场工具的推出之后。这也是我们进入…

(十七)Async异步和多线程-语言进阶1

&#xff08;十七&#xff09;Async异步和多线程-语言进阶1一、进程-线程-多线程&#xff0c;同步和异步1.概念2.同步和异步3.异步与多线程异同点二、委托启动异步调用1.同步方法2.异步方法三、多线程的特点四、异步的回调和状态参数1.顺序控制2.状态参数五、异步等待三种方式1…

开学季,护眼灯什么牌子好?2023年护眼台灯推荐

2023年开始了&#xff0c;时间飞逝&#xff0c;而每个父母都越来越紧张自家娃的学业情况&#xff0c;我国近视人数超过7亿人&#xff0c;而儿童时期是视力发育的关键时期&#xff0c;为啥有那么高的近视率呢&#xff1f;主要是用眼过度&#xff0c;以及用眼习惯&#xff0c;而现…

微信小程序——模板与配置,数据绑定,事件绑定

一.数据绑定1.数据绑定的基本原则在data中定义数据在WXML中使用数据2.在data中定义页面的数据在页面对应的.js文件中&#xff0c;把数据定义到data对象中即可3. Mustache 语法的格式把 data 中的数据绑定到页面中渲染&#xff0c;使用 Mustache 语法&#xff08;双大括号&#…

想提高办公效率?可试试java开源工作流框架

在数据化管理越来越规范的当今社会&#xff0c;采用优质的办公软件平台能提高企业的办公协作效率&#xff0c;因而受到了广泛的欢迎和喜爱。那么&#xff0c;什么是java开源工作流框架&#xff1f;我们可以从它的特点、发展前景等方面来加以了解&#xff0c;一起来了解这一产品…

微信公众号运营工具有哪些?赶紧收藏

再厉害的公众号运营大神背后都有一套宝藏工具大全&#xff0c;辅助运营人一路披荆斩棘&#xff0c;堪称神器&#xff01; 我相信网上一搜也能出来很多的运营工具或是网站&#xff0c;但是这里再来给大家来一个大汇总&#xff0c;这次整理绝对是非常详细和实用的&#xff0c;纯…

Fiddler中常用的功能

Fiddler中常用的功能如下&#xff1a; 停止抓包-清空会话窗-内容过滤请求-解码-设置断点 一、 停止抓包 二、清空会话窗 方法一&#xff0c;工具栏工具&#xff1a; 方法二&#xff0c;命令行形式&#xff1a; 当然&#xff0c;命令行工具也还支持其他命令的输入&#xff0c…

word排版技巧:如何将段中文字生成标题目录

在许多Word文档里面&#xff0c;目录页是非常重要的一页内容&#xff0c;因为目录页展示的是当前文档的内容框型和结构。通过目录页&#xff0c;我们能知道这个文档主要分为哪几部分。就像看书一样&#xff0c;起到了检索的作用。今天&#xff0c;我们就来给大家分享一个偏门的…

焕新古文化传承之路,AI为古彝文识别赋能

目录1 古彝文与古典保护2 古文识别的挑战2.1 西文与汉文OCR2.2 古彝文识别难点3 合合信息&#xff1a;古彝文保护新思路3.1 图像矫正3.2 图像增强3.3 语义理解3.4 工程技巧4 总结1 古彝文与古典保护 彝文指的是云南、贵州、四川等地的彝族人使用的文字&#xff0c;区别于现代意…

【Linux】常用基本指令(续)

文章目录&#x1f3aa; Linux下基本指令1.1 &#x1f680; whoami1.2 &#x1f680; tree1.3 &#x1f680; echo(浅析)1.4 &#x1f680; zip/unzip1.5 &#x1f680; tar1.6 &#x1f680; bc1.7 &#x1f680; history1.8 &#x1f680; uname1.9 &#x1f680; nano1.10 &a…

数据结构基础之动态顺序表详解

文章目录前言一、动态顺序表的概念二、顺序表的结构体三、基本接口1.SeqListInit&#xff08;初始化数组&#xff09;2.SeqListDestory&#xff08;销毁数组&#xff09;3. SeqListCheckCapacity&#xff08;检查改顺序表是否需要扩容&#xff09;4.SeqListPushBack&#xff08…

用真实业务场景告诉你,高并发下如何设计数据库架构?

目录&#xff1a; 用一个创业公司的发展作为背景引入用多台服务器来分库支撑高并发读写大量分表来保证海量数据下查询性能读写分离来支撑按需扩容及性能提升高并发下的数据库架构设计总结 这篇文章&#xff0c;我们来聊一下对于一个支撑日活百万用户的高并系统&#xff0c;他…

如何搭建云进销存-销售管理系统?

1、简介1.1、案例简介本文将介绍&#xff0c;如何搭建云进销存-销售管理。1.2、应用场景云进销存-销售管理应用支持移动端扫码录入&#xff0c;提高开单效率&#xff0c;保证开单质量。支持自定义优先级自动取价&#xff0c;灵活满足不同商品价格管理。2、设置方法2.1、表单搭建…