2018年全国多校算法寒假训练营练习比赛(第五场):D 集合问题(并查集)

链接:https://www.nowcoder.com/acm/contest/77/D
来源:牛客网

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足:

若x在集合A中,则a-x必须也在集合A中。

若x在集合B中,则b-x必须也在集合B中。

输入描述:

第一行 三个数 n a b  1<=n<=1e5  1<=a,b<=1e9
第二行 n个数 p1 p2 p3...pn 1<=pi<=1e9

输出描述:

如果可以恰好分开就输出第一行 YES
然后第二行输出 n个数 分别代表pi 是哪个集合的  0 代表是A集合 1代表是B 集合
不行就输出NO
放在哪个集合都可以的时候优先放B
示例1

输入

4 5 9
2 3 4 5

输出

YES
0 0 1 1
示例2

输入

3 3 4
1 2 4

输出

NO
题意不多说了,这题要用到并查集,并查集学过了,但却不会应用,很是可悲。具体细节看代码

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<vector>
using namespace std;
#define LL long long
#define inf 0x3ffffffff
const int N=100005;
int s[N],far[N];
map<int,int>mpp;
int finf(int a)
{
    return far[a]==a?a:far[a]=finf(far[a]);
}
void uion(int a,int b)
{
    int fa=finf(a);
    int fb=finf(b);
    if(fa!=fb) far[fb]=fa;
}
int main()
{
    int n,a,b,fa,fb;
    while(~scanf("%d%d%d",&n,&a,&b))
    {
        mpp.clear();
        for(int i=0;i<=n+1;i++)//初始化
            far[i]=i;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&s[i]);
            mpp[s[i]]=i;
        }
        //这个for循环将数组分为两组或者一组
        for(int i=1;i<=n;i++)
        {
            if(mpp[b-s[i]]) uion(i,mpp[b-s[i]]);
            else uion(i,0);//第一组
            if(mpp[a-s[i]]) uion(i,mpp[a-s[i]]);
            else uion(i,n+1);//第二组
        }
        fa=finf(0);
        fb=finf(n+1);
        if(fa==fb)//如果两组的根节点相同,那么说明有一个或多个数需要同时在两个数组里
        {
            printf("NO\n");
            continue;
        }
        else
        {
            printf("YES\n");
            for(int i=1;i<=n;i++)
            {
                if(i!=1) printf(" ");
                if(fa==finf(i)) printf("0");
                else printf("1");
            }
            printf("\n");
        }
    }
}
//3 4 8
//1 3 5

//4 5 9
//2 3 4 5

//3 3 8
//1 2 5







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值