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