首页 > 其他分享 >并查集

并查集

时间:2023-05-24 13:12:17浏览次数:31  
标签:int res 查集 cin pb pa find

6-1 并查集
///find函数可能有点难理解,自己尝试画下图随便理解好吧
///M是合并,Q是询问是否在一个树中
#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,m;
int q[N];
int find(int x)
{
    if(q[x]!=x) q[x]=find(q[x]));///如果x不是树的头结点,向上循环查找到头结点为止.
    ///可以自己画图理解一下;
    return q[x];
}
int  main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        q[i]=i;
    while(m--)
    {
        char op[2];
        int a,b;
        scanf("%s%d%d",&op,&a,&b);
        if(op[0]=='M') q[find(a)]=find(b);
        else
        {
            if(find(a)==find(b))
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }
    }
    return 0;
}
6-2 查并集,但是可能输出长度
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m;
int p[N],size[N];
int find(int x)
{
    if(p[x]!=x) p[x]=find(p[x]);
    return p[x];
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        p[i]=i;
        size[i]=1;
    }
    while(m--)
    {
        ///C为合并,Q1为 检查是否在同一区间,Q2检查长度;
        char op[2];
        scanf("%s",&op);
        int a,b;
        if(op[0]=='C')
        {
            cin>>a>>b;
            if(find(a)==find(b)) continue;///特判
            size[find(b)]+=size[find(a)];
            p[find(a)]=find(b);
        }
        else if(op[1]=='1')
        {
            cin>>a>>b;
            if(find(a)==find(b))
                cout<<"YES"<<endl;
            else
                cout<<"No"<<endl;
        }
        else if(op[1]=='2')
        {
            cin>>a;
            cout<<size[find(a)]<<endl;
        }
    }
}
6-3 食物链
https://www.luogu.com.cn/problem/P2024
///这题是真难,看视频加理解一共花了俩小时
#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,res=0;
int p[N],d[N];
int find(int x)
{
    if(p[x]!=x)///与以往不同,这里的d数组刚开始的作用是,x节点与父节点的距离,经过find函数递归之后
                    ///d数组变成了,x节点到头节点的距离,这样就可以来判断是不是同一类和接下来做题了
    {
        int t=find(p[x]);
        d[x]+=d[p[x]];///因为要用到p[x],所以先储存;
        p[x]=t;
    }
    return p[x];
}
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++)
        p[i]=i;
    while(m--)
    {
        int a,b,c;
        cin>>c>>a>>b;
        if(a>n||b>n) res++;
        else
        {
            if(c==1)
            {
                int pa=find (a),pb=find(b);
                if(pa==pb&&(d[a]-d[b])%3) res++;///3个一循环;如果A和B是同类,而且他俩已经在合并过了,那么两者的距离相减,如果余三不得0那么就是错的;
                else
                {
                    p[pa]=pb;
                    d[pa]=d[b]-d[a];
                }
            }
            else
            {
                int pa=find(a),pb=find(b);
                if(pa==pb&&(d[a]-d[b]-1)%3) res++;
                else if(pa!=pb)
                {
                    p[pa]=pb;
                    d[pa]=d[b]+1-d[a];
                }
            }
        }
    }
    cout<<res;
    return 0;
}
6-4 自动程序检测装置
https://www.luogu.com.cn/problem/P1955
///这个题是我得知有查并集这个算法的起初
///查并集+离散化,题目i和j都开到10的九次方了,不用离散化等着爆吧
///本题思路
#include<bits/stdc++.h>
using namespace std;
const int N=400010;
int t,n;
int a[2*N],p[N],d[2*N],b[N],c[N];
int find(int x)///典
{
    if(p[x]!=x)
        p[x]=find(p[x]);
    return p[x];
}
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a[2*i-1]>>a[2*i]>>c[i];
            d[2*i-1]=a[2*i-1],d[2*i]=a[2*i];
        }
    sort(d+1,d+2*n+1);
    int h=0;
    b[0]=-1;
    for(int i=1;i<=2*n;i++)
        if(b[h]!=d[i]) b[++h]=d[i];///离散化完成,用了两次这个离散化模板了,感觉yxc老师的那个离散化模板用不了一点
    for(int i=1;i<=h;i++)
        p[i]=i;///更新爹节点
    for(int i=1;i<=n;i++)
    {
        if(c[i]==0)
            continue;
        int x=lower_bound(b+1,b+h+1,a[2*i-1])-b;
        int y=lower_bound(b+1,b+h+1,a[2*i])-b;
        if(find(x)==find(y)) continue;
        else
            p[find(x)]=find(y);///将所有相等的元素,放进树里面;接下来的就是狠狠的查找有没有内鬼
    }
    bool f=false;
    for(int i=1;i<=n;i++)
    {
        if(c[i]==1)
            continue;
        int x=lower_bound(b+1,b+h+1,a[2*i-1])-b;
        int y=lower_bound(b+1,b+h+1,a[2*i])-b;
        if(find(x)==find(y))///查找内鬼,如果有人在相等的树里面,就是内鬼!
        {
            cout<<"NO"<<endl;
            f=true;
            break;
        }
    }
    if(!f)
        cout<<"YES"<<endl;
}
    return 0;
}
6-6 A-bugs
http://bailian.openjudge.cn/practice/2492/
    ///此题考察并查集的应用,考察的是加权并查集,类似于食物链,需要考虑两者之间存在距离关系


///大题思路:每当输出两个数字是,代表这两个数字之间肯定是异性关系(如果两者满足距离为奇数)
///每当新的数加入到另一个树上时,如果符合条件,那么就意味这两者的距离之差至少为1,并且都是奇数,再向下拓展一位,也就是距离为偶数的,就是同性
///可以用da-db%2来判断,如果两者在一个树上并且满足这个条件,这两个人就是同性!

#include<bits/stdc++.h>
using namespace std;
const int N=10010;
int n,m,t;
int p[N],d[N];
int find(int x)
{
    if(x!=p[x])
    {
        int t=find(p[x]);
        d[x]+=d[p[x]];
        p[x]=t;
    }
    return p[x];
}
int main()
{
    cin>>t;
    int res=1;
    while(t--)
    {
        cin>>n>>m;
        for(int i=1;i<=n;i++)
            p[i]=i;
        memset(d,0,sizeof d);
        bool f=false;
        while(m--)
        {
            int a,b;
            cin>>a>>b;
            int pa=find(a),pb=find(b);
            if(pa==pb&&(d[a]-d[b])%2==0)
                f=true;
            else
            {
                p[pa]=p[b];
                d[pa]=d[b]+1-d[a];
            }
        }
        if(f)
        {
            printf("Scenario #%d:\n",res++);
            cout<<"Suspicious bugs found!"<<endl;
        }
        else
        {
            printf("Scenario #%d:\n",res++);
            cout<<"No suspicious bugs found!"<<endl;
        }
        cout<<endl;
    }
    return 0;
}

 

标签:int,res,查集,cin,pb,pa,find
From: https://www.cnblogs.com/o-Sakurajimamai-o/p/17427994.html

相关文章

  • 并查集
    并查集并查集是一种用于处理集合合并和查询的数据结构,常用于连通性问题。它可以动态地添加和合并集合,并快速地查询两个元素是否在同一个集合中。————chatGPT并查集被很多OIer认为是最简洁而优雅的数据结构之一,主要用于解决一些元素分组的问题......
  • 【CF1012E】【LOJ2818】Cycle Sort(并查集)
    Description给定一个⻓为nn的数列,你可以多次进行如下操作:选定kk个不同的下标i1,i2…iki1,i2......
  • 并查集概述
      并查集基础一、概念及其介绍并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题。并查集的思想是用一个数组表示了整片森林(parent),树的根节点唯一标识了一个集合,我们只要找到了某个元素的的树根,就能确定它在哪个集合里。二、适用说明并查集用在一些有......
  • [Week 19]每日一题(C++,数学,并查集,动态规划)
    目录[Daimayuan]T1倒数第n个字符串(C++,进制)输入格式输出格式样例输入样例输出解题思路[Daimayuan]T2排队(C++,并查集)输入格式输出格式样例输入1样例输出1样例输入2样例输出2样例输入3样例输出3数据规模解题思路[Daimayuan]T3素数之欢(C++,BFS)数据规模输入格式输出格式样例输入样......
  • 并查集的操作
    //并查集#include<stdio.h>#defineSIZE100intUFSets[SIZE];voidinitial(intS[])//初始化并查集全部设为-1即每一个元素都是独立的{for(inti=0;i<SIZE;i++){S[i]=-1;}}intFind(intS[],intx)//查找元素操作返回x所属根节点x指的是......
  • 带权并查集
    做了cf上一道题后发现我对并查集的理解不够深刻,顺带把带权并查集学一下。并查集初始化:对于一个集合A的所有元素,我们知道对于其中任意一个元素i,i€A。此时,我们可以认为i与A之间存在一条虚边,如果有新的元素要加入集合A,将该元素与A建一条边即可。这条边我们用数组fa[i]......
  • 6795 Connected Components 并查集
     描述 编写一个程序,读取SNS(社交网络服务)中的关系,并判断给定的用户对是否可以通过网络相互访问。 输入 第一行给出了两个整数n和m。n是SNS中的用户数,m是SNS中的关系数。SNS中的用户由ID0,1,...,n-1标识。在接下来的m行中,给出了关系。每个关系由两个整......
  • 2649: More is better 并查集
    王先生想要一些男孩帮助他完成一个项目。因为项目比较复杂,男生来的越多越好。当然有一定的要求。王先生选择了一个足够容纳孩子们的房间。没有被选中的男孩必须立即离开房间。一开始房间里有10000000个男孩,编号从1到10000000。经过王先生的选择,他们中仍然在这个房间里的任何两个......
  • 7922: 江湖 并查集
    描述 江湖上散落着各式各样的大侠,有上千个之多。他们没有什么正当职业,整天背着剑在外面走来走去,碰到和自己不是一路人的,就免不了要打一架。但大侠们有一个优点就是讲义气,绝对不打自己的朋友。而且他们信奉“朋友的朋友就是我的朋友”,只要是能通过朋友关系串联起来的,不管拐了多......
  • 并查集
    并查集将两个集合合并询问两个元素是否在一个集合当中基本原理:每个集合用一颗树来表示,树根的编号就是整个集合的编号.每个节点存储它的父节点,p[x]表示x的父节点.①如何判断树根if(p[x]==x)②如何求x的集合编号while(p[x]!=x)x=p[x]③如何合并......