Codeforces 870E Points, Lines and Ready-made Titles:并查集【两个属性二选一】
题目链接:http://codeforces.com/problemset/problem/870/E
题意:
给出平面坐标系上的n个点。
对于每个点,你可以画一条经过这个点的横线或竖线或什么都不画。
两条重合的直线算作一条直线。
问你能画出多少种不同的图案。
题解:
将所有横坐标或纵坐标相同的两点之间连边。
对于一个连通块,设这个连通块中不同的横坐标个数为sx,不同的纵坐标个数为sy。
有可能画出的线的个数即为sx + sy。
可以发现,如果一个联通块中有环(即siz[fa] >= sx + sy)
那么这sx + sy条边可以同时画出。
否则必然有一条边不能画出。
所以当前连通块的答案:有环为2^(sx+sy),无环为2^(sx+sy) - 1。
将所有连通块的答案乘起来即为总答案。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 #include <set> 6 #define MAX_N 100005 7 #define MAX_E 200005 8 #define MOD 1000000007 9 10 using namespace std; 11 12 struct Coor 13 { 14 int x,y,id; 15 Coor(int _x,int _y,int _id) 16 { 17 x=_x; y=_y; id=_id; 18 } 19 Coor(){} 20 }; 21 22 int n; 23 int par[MAX_N]; 24 int siz[MAX_N]; 25 long long ans=1; 26 long long pw[MAX_E]; 27 Coor c[MAX_N]; 28 set<int> sx[MAX_N]; 29 set<int> sy[MAX_N]; 30 31 bool cmp1(const Coor &a,const Coor &b) 32 { 33 return a.y!=b.y ? a.y<b.y : a.x<b.x; 34 } 35 36 bool cmp2(const Coor &a,const Coor &b) 37 { 38 return a.x!=b.x ? a.x<b.x : a.y<b.y; 39 } 40 41 void read() 42 { 43 cin>>n; 44 for(int i=1;i<=n;i++) 45 { 46 cin>>c[i].x>>c[i].y; 47 c[i].id=i; 48 } 49 } 50 51 void init_union_find() 52 { 53 for(int i=1;i<=n;i++) 54 { 55 par[i]=i; 56 siz[i]=1; 57 } 58 } 59 60 int find(int x) 61 { 62 return par[x]==x ? x : par[x]=find(par[x]); 63 } 64 65 void unite(int x,int y) 66 { 67 int px=find(x); 68 int py=find(y); 69 if(px==py) return; 70 siz[py]+=siz[px]; 71 par[px]=py; 72 } 73 74 void build() 75 { 76 sort(c+1,c+1+n,cmp1); 77 for(int i=1;i<n;i++) 78 { 79 if(c[i].y==c[i+1].y) 80 { 81 unite(c[i].id,c[i+1].id); 82 } 83 } 84 sort(c+1,c+1+n,cmp2); 85 for(int i=1;i<n;i++) 86 { 87 if(c[i].x==c[i+1].x) 88 { 89 unite(c[i].id,c[i+1].id); 90 } 91 } 92 } 93 94 void cal_pow() 95 { 96 pw[0]=1; 97 for(int i=1;i<MAX_E;i++) pw[i]=(pw[i-1]<<1ll)%MOD; 98 } 99 100 void cal_set() 101 { 102 for(int i=1;i<=n;i++) 103 { 104 sx[find(c[i].id)].insert(c[i].x); 105 sy[find(c[i].id)].insert(c[i].y); 106 } 107 } 108 109 inline long long mod(long long x) 110 { 111 return (x%MOD+MOD)%MOD; 112 } 113 114 void cal_ans() 115 { 116 for(int i=1;i<=n;i++) 117 { 118 int fa=find(i); 119 if(fa==i) 120 { 121 int edge=sx[fa].size()+sy[fa].size(); 122 if(siz[fa]>=edge) ans=mod(ans*mod(pw[edge])); 123 else ans=mod(ans*mod(pw[edge]-1)); 124 } 125 } 126 } 127 128 void work() 129 { 130 init_union_find(); 131 build(); 132 cal_pow(); 133 cal_set(); 134 cal_ans(); 135 cout<<ans<<endl; 136 } 137 138 int main() 139 { 140 read(); 141 work(); 142 }