題目連結: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 }