首先最大的数字一定小于给定的,否则必须有或者负值存在。

显然数对一定是存在于两个集合中的某一个。

所以对于每个给的数,若中任意一个出现,就必须配对。

这样就变成了并查集,即能配对的数对合并并查集。

每个数字用出现的位置来代替,相当于一个没有去重的离散化。

这个用什么二分啊,平衡树啊,啊啥的都行,复杂度不会超过的。

我就用了,挺好。

那么对于所给的数,如果这个数不能放入集合(题目优先考虑集合),那么就一定是在集合中。

如果在中都不能放的数,那么两个集合的并查集就一定会相交,通过这个就可以判断能否满足条件。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<map>
#define MAXN 100010
using namespace std;
int n,A,B,a,b,maxn=0,val[MAXN],fa[MAXN];
map<int,int> pos;
char tp[100000],*p1=tp,*p2=tp;
inline char get_char(){
    return p1==p2&&(p2=(p1=tp)+fread(tp,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    int date=0,w=1;char c=0;
    while(c<'0'||c>'9'){if(c=='-')w=-1;c=get_char();}
    while(c>='0'&&c<='9'){date=date*10+c-'0';c=get_char();}
    return date*w;
}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void uniun(int x,int y){x=find(x);y=find(y);if(x!=y)fa[y]=x;}
void work(){
    if(maxn>=max(A,B)){
        printf("NO\n");
        return;
    }
    for(int i=1;i<=n;i++){
        if(pos[B-val[i]])uniun(i,pos[B-val[i]]);
        else uniun(a,i);
        if(pos[A-val[i]])uniun(i,pos[A-val[i]]);
        else uniun(b,i);
    }
    a=find(a);b=find(b);
    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 ");
        }
        printf("\n");
    }

}
void init(){
    n=read();A=read();B=read();
    a=n+1;b=n+2;
    fa[a]=a;fa[b]=b;
    for(int i=1;i<=n;i++){
        val[i]=read();
        fa[i]=i;
        pos[val[i]]=i;
        maxn=max(maxn,val[i]);
    }
}
int main(){
    init();
    work();
    return 0;
}