首先最大的数字一定小于给定的,否则必须有
或者负值存在。
显然数对一定是存在于
两个集合中的某一个。
所以对于每个给的数,若
中任意一个出现,就必须配对。
这样就变成了并查集,即能配对的数对合并并查集。
每个数字用出现的位置来代替,相当于一个没有去重的离散化。
这个用什么二分啊,平衡树啊,啊啥的都行,复杂度不会超过
的。
我就用了,挺好。
那么对于所给的数,如果这个数不能放入集合(题目优先考虑
集合),那么就一定是在
集合中。
如果在中都不能放的数,那么两个集合的并查集就一定会相交,通过这个就可以判断能否满足条件。
附代码:
#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;
}
京公网安备 11010502036488号