Codeforces 870E Points, Lines and Ready-made Titles:並查集【兩個屬性二選一】

Leohh發表於2018-02-25

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

 

相關文章