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 }
原文地址:https://www.cnblogs.com/Leohh/p/8468731.html