(并查集\状态压缩)CodeForces - 469D Two Sets

Little X has n distinct integers: p1,?p2,?...,?pn. He wants to divide all of them into two sets A and B. The following two conditions must be satisfied:

  • If number x belongs to set A, then number a?-?x must also belong to set A.
  • If number x belongs to set B, then number b?-?x must also belong to set B.

Help Little X divide the numbers into two sets or determine that it‘s impossible.

Input

The first line contains three space-separated integers n,?a,?b (1?≤?n?≤?105; 1?≤?a,?b?≤?109). The next line contains n space-separated distinct integers p1,?p2,?...,?pn (1?≤?pi?≤?109).

Output

If there is a way to divide the numbers into two sets, then print "YES" in the first line. Then print n integers: b1,?b2,?...,?bn (bi equals either 0, or 1), describing the division. If bi equals to 0, then pi belongs to set A, otherwise it belongs to set B.

If it‘s impossible, print "NO" (without the quotes).

Example

Input

4 5 92 3 4 5

Output

YES0 0 1 1

Input

3 3 41 2 4

Output

NO

Note

It‘s OK if all the numbers are in the same set, and the other one is empty.

注意到如果x存在于A果a-x、b-x(如果存在)也必须存在在A,如果a-(b-x) 、b-(a-x)存在也必须在A……即所有数可以划分为若干个集合,每个集合中的元素必须同时属于A或B。这可以通过并查集维护。如果某数x,a-x,b-x都不存在那么这个数无法放到A、B任何一个,直接输出NO即可。

接下来维护并查集的状态,采用状态压缩,用两位2进制数表示可否放到A、B集合中。对于每个数x,如果a-x存在则其可以放在集合A,如果b-x存在则其可以放在集合B。对每个并查集取其集合内所有可行状态的交集。显然并查集之间是不再存在互相影响的。如果每个并查集可行状态非0就表明一定存在符合题意的分配方式,任取每个集合的任意可行分配即可。

  1 #include <iostream>
  2 #include <string>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <queue>
  8 #include <set>
  9 #include <map>
 10 #include <list>
 11 #include <vector>
 12 #include <stack>
 13 #define mp make_pair
 14 //#define P make_pair
 15 #define MIN(a,b) (a>b?b:a)
 16 //#define MAX(a,b) (a>b?a:b)
 17 typedef long long ll;
 18 typedef unsigned long long ull;
 19 const int MAX=1e5+5;
 20 const int MAX_V=25;
 21 const int INF=2e9+5;
 22 const double M=4e18;
 23 using namespace std;
 24 const int MOD=1e9+7;
 25 typedef pair<ll,int> pii;
 26 const double eps=0.000000001;
 27 #define rank rankk
 28 map<int,int> par;//父亲
 29 map<int,int> rank;//树的高度
 30 //初始化n个元素
 31 map<int,bool> chu;
 32 map<int,int> st;
 33 int an[MAX];
 34 void init(int n)
 35 {
 36     for(int i=1;i<n;i++)
 37     {
 38         par[i]=i;
 39         rank[i]=0;
 40     }
 41 }
 42 //查询树的根,期间加入了路径压缩
 43 int find(int x)
 44 {
 45     if(!par[x])
 46     {
 47         rank[x]=0;
 48         return par[x]=x;
 49     }
 50     if(par[x]==x)
 51         return x;
 52     else
 53         return par[x]=find(par[x]);
 54 }
 55 //合并x和y所属的集合
 56 void unite(int x,int y)
 57 {
 58     x=find(x);
 59     y=find(y);
 60     if(x==y)
 61         return ;
 62     if(rank[x]<rank[y])
 63         par[x]=y;
 64     else
 65     {
 66         par[y]=x;
 67         if(rank[x]==rank[y])
 68             rank[x]++;
 69     }
 70 }
 71 //判断x和y是否属于同一个集合
 72 bool same(int x,int y)
 73 {
 74     return find(x)==find(y);
 75 }
 76 int n,a,b;
 77 int x[MAX];
 78 int main()
 79 {
 80     scanf("%d%d%d",&n,&a,&b);
 81     for(int i=1;i<=n;i++)
 82     {
 83         scanf("%d",&x[i]);
 84         chu[x[i]]=true;
 85     }
 86     for(int i=1;i<=n;i++)
 87         st[x[i]]=0;
 88     for(int i=1;i<=n;i++)
 89     {
 90         bool sta=false;
 91         if(chu[a-x[i]])
 92         {
 93             sta=true;
 94             unite(x[i],a-x[i]);
 95             st[x[i]]|=1;
 96         }
 97         if(chu[b-x[i]])
 98         {
 99             sta=true;
100             unite(x[i],b-x[i]);
101             st[x[i]]|=2;
102         }
103         if(!sta)
104             return 0*printf("NO\n");
105     }
106     for(int i=1;i<=n;i++)
107     {
108         st[find(x[i])]&=st[x[i]];
109     }
110     for(int i=1;i<=n;i++)
111         if(!st[x[i]])
112             return 0*printf("NO\n");
113     printf("YES\n");
114     for(int i=1;i<=n;i++)
115     {
116         if(st[find(x[i])]&1)
117             printf("0 ");
118         else
119             printf("1 ");
120     }
121     printf("\n");
122     return 0;
123 }
时间: 2024-10-08 01:33:58

(并查集\状态压缩)CodeForces - 469D Two Sets的相关文章

hdu 1558 线段相交+并查集路径压缩

Segment set Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3457    Accepted Submission(s): 1290 Problem Description A segment and all segments which are connected with it compose a segment set.

snnu(1110) 传输网络 (并查集+路径压缩+离线操作)

1110: 传输网络 Time Limit: 3 Sec  Memory Limit: 512 MBSubmit: 43  Solved: 18[Submit][Status][Web Board] [Edit] Description Byteland国家的网络单向传输系统可以被看成是以首都Bytetown为中心的有向树,一开始只有Bytetown建有基站,所有其他城市的信号都是从Bytetown传输过来的.现在他们开始在其他城市陆续建立了新的基站,命令“C x“代表在城市x建立了一个新的基站

并查集 路径压缩

使用并查集查找时,如果查找次数很多,那么使用朴素版的查找方式肯定要超时.比如,有一百万个元素,每次都从第一百万个开始找,这样一次运算就是10^6,如果程序要求查找个一千万次,这样下来就是10^13,肯定要出问题的. 这是朴素查找的代码,适合数据量不大的情况: int findx(int x){ int r=x; while(parent[r] !=r) r=parent[r]; return r;} 下面是采用路径压缩的方法查找元素: int find(int x) //查找x元素所在的集合,回

poj 2513 Colored Sticks(欧拉回路 并查集 路径压缩 字典树)(困难)

Colored Sticks Time Limit: 5000MS   Memory Limit: 128000K Total Submissions: 32545   Accepted: 8585 Description You are given a bunch of wooden sticks. Each endpoint of each stick is colored with some color. Is it possible to align the sticks in a st

并查集路径压缩与启发式合并

[程序清单] 初始化: for i:=1 to n do father[i]:=i; 因为每个元素属于单独的一个集合,所以每个元素以自己作为根结点. 寻找根结点编号并压缩路径: function getfather(v : integer) : integer; begin if father[v]=v then exit(v); father[v]:=getfather(father[v]); getfather:=father[v]; end; 合并两个集合: proceudre merge

HDU 3635 Dragon Balls(并查集--路径压缩拓展应用)

题目大意: 初始时,有n个龙珠,编号从1到n,分别对应的放在编号从1到n的城市中. 现在又2种操作: T A B,表示把A球所在城市全部的龙珠全部转移到B城市.(第一次时,因为A球所在的城市只有一个球,所以只移动1个,如果有多个,则全部移动). Q A,表示查询A.要求得到的信息分别是:A现在所在的城市,A所在城市的龙珠数目,A转移到该城市移动的次数(如果没有移动就输出0) 思路:并查集,难点在于求龙珠的转移次数,可以在路径压缩的过程中沿着递归路径累加. //Accepted 1740 KB 5

并查集 路径压缩(具体解释)

拿HDU 1232举例. 题解: 首先在地图上给你若干个城镇.这些城镇都能够看作点,然后告诉你哪些对城镇之间是有道路直接相连的.最后要解决的是整幅图的连通性问题.比方任意给你两个点,让你推断它们是否连通,或者问你整幅图一共同拥有几个连通分支,也就是被分成了几个互相独立的块.像畅通project这题,问还须要修几条路.实质就是求有几个连通分支.假设是1个连通分支,说明整幅图上的点都连起来了,不用再修路了.假设是2个连通分支,则仅仅要再修1条路,从两个分支中各选一个点,把它们连起来,那么全部的点都是

并查集 路径压缩(详解)

拿HDU 1232举例. 题解: 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的.最后要解决的是整幅图的连通性问题.比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块.像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支.如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了:如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了:如果

poj1988Cube Stacking(并查集+路径压缩)

本题依然是并查集的应用,与上一个监狱的问题不同,本题计算的是距离,通过记录通往自己父节点距离的相对距离,与父节点到根节点(代表元素)的距离依次相加 路径压缩时每次都要更新节点. #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; const int maxn=30001; int p; struct { int fat