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

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

题目描述

给你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

题解:
若有a-x2=x1,b-x3=x1;则x1可以与x2放到a中,
也可与x3放到b中,但是无论怎么放最后x1,x2,x3一定在同一集合中。
证明:一定不存在另一个数可以使a-x2=x0(x1与x2在a中的匹配是唯一的)。
同理x1与x3在b中的匹配也是唯一的。但是可能存在一个数使得
b-x2=x0,即x2与x0在b中匹配,那么此时x2与x0在b中(假设仅存在这四个数),
那么剩下的x1,x3也只能在b中匹配。
若存在一个数使a-x3=x0,则这四个数存在于a中。
若即有a-x3=x0,又有b-x2=x0,则这四个数可都在a或b中,据题意,b优先,
所以都在b中。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+7;
int par[maxn],t[maxn];
map<int,int>mp;
void init()
{
    for(int i=0;i<maxn;i++)
        par[i]=i;
}
int find(int x)
{
    if(par[x]==x)return x;
    return par[x]=find(par[x]);
}
void unite(int x,int y)
{
    x=find(x);y=find(y);
    if(x!=y)
        par[x]=y;
}
int main()
{
    init();
    int n,a,b;scanf("%d%d%d",&n,&a,&b);
    int ma=0;
    for(int i=1;i<=n;i++)
    {
        int x;scanf("%d",&t[i]);
        ma=max(ma,t[i]);
        mp[t[i]]=i;
    }
    if(ma>=max(a,b))
    {
        printf("NO\n");
        return 0;
    }
    for(int i=1;i<=n;i++)
    {
        if(mp[a-t[i]])unite(i,mp[a-t[i]]);
        else unite(i,n+1);
        if(mp[b-t[i]]) unite(i,mp[b-t[i]]);
        else unite(i,0);
    }
    int A=find(0),B=find(n+1);
    if(A==B) printf("NO\n");
    else
    {
        printf("YES\n");
        for(int i=1;i<=n;i++)
        {
            if(find(i)==A)printf("0");
            else printf("1");//必须先判断A,因为剩下的不一定
            //都已经加入到了B中,存在一些A,B都可以的情况
            if(i!=n)printf(" ");
            else printf("\n");
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值