codeforces 468B two set(并查集)

链接

B. Two Sets

题意

给两个集合A B,两个数a b,n个数x,分配n个数到两个集合,要求x , a-x在同一个集合,x , b-x在同一个集合,属于A集合的数输出0,B的输出1,无解输出NO,空集也算一个集合,所以存在所有数都在一个集合。

做法

这有一个样例

input
6 5 9
1 2 3 4 5 8
output
YES
1 0 0 1 1 1

[1 4]\inA,[4 5]\inB,[1,8]\inB,所以只能把1 4都放进B集合

首先,能在A里面处理的就放入A,否则放入B,能在B里面处理的就放入B,否则放入A,如果x只能在B出现然而b-x在A里面则把b-x拿来B,你是不是担心把b-x从A里拿掉了,那a-(b-x)岂不是没有配对了?如果是这样的话那就是不合法的呗,不然后面还会把a-(b-x)从A中拿给B的,如上面的样例。如果两个集合里有重复元素则不合法。

代码

#include<bits/stdc++.h>
using namespace std;
#define M 111000
int fa[M], num[M];
int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}
int main() {
    int n, a, b;
    while (cin >> n >> a >> b) {
        map<int, int> mp;
        for (int i = 1; i <= n; i++) {
            cin >> num[i];
            mp[num[i]] = i;
        }
        for (int i = 1; i <= n + 2; i++)
            fa[i] = i;
        int x;
        for (int i = 1; i <= n; i++) {
            x = find(i);
            if (mp[a - num[i]]) fa[x] = find(mp[a - num[i]]);//如果a-num[i]存在的话,则把num[i]和a-num[i]放进a集合
            else fa[x] = find(n + 1);//否则放在b集合
            x = find(i);//为什么不直接用上面的x,因为合并后fa[x]已经变化了
            if (mp[b - num[i]]) fa[x] = find(mp[b - num[i]]);//如果b-num[i]存在的话,则把num[i]和b-num[i]放进b集合
            else fa[x] = find(n + 2);//否则放在a集合
        }
        if (find(n + 1) == find(n + 2))//如果两个集合有重复元素则不合法
            cout << "NO\n";
        else {
            cout << "YES\n";
            printf("%d", find(1) == find(n + 1));
            for (int i = 2; i <= n; i++)
                printf(" %d", find(i) == find(n + 1));
            cout << endl;
        }
    }
    return 0;
}
posted @ 2017-04-18 11:24  April_AA  阅读(602)  评论(0编辑  收藏  举报