题意:
给n个点,可以过每个点做x轴垂线,平行线,问一共多少种不同图像。
题解:
(直接copy官网的吧,下面有翻译):
Let’s build graph on points. Add edge from point to left, right, top and bottom neighbours (if such neigbour exist). Note that we can solve problem independently for each connected component and then print product of answer for components. So we can consider only connected graphs without loss of generality.
Let’s define X as number of different x-coords, Y as number of different y-coords.
What if graph contains some cycle? Let’s consider this cycle without immediate vertices (vertices that lie on the same line with previous and next vertices of cycle). Draw a line from each such vertex to the next vertex of cycle (and from last to the first). We got all lines that are corresponding to x-coords and y-coords of vertices of cycle. Let’s prove by induction that we can got all such lines from the whole graph
Run depth-first search from vertices of cycle. Let we enter in some vertex that is not from cycle. It mush have at least one visited neighbour. By induction for graph consisting of visited vertices we can get all lines. So there is line from visited neighbour. Draw line in another direction and continue depth-first search. Sooner or later we will get all lines for the whole graph. Please note that intermediate vertices of cycle will be processed correctly too.
If we can get all lines the we can get all subsets of lines. Answer for cyclic graph is 2X + Y.
Now look at another case — acyclic graph or tree. We can prove that we can get any incomplete subset of lines.
Let’s fix subset and some line not from this subset. Just draw this line without restriction. By similar induction as in cyclic graph case we can prove that we can get all lines (but fixed line doesn’t exist really).
Now let’s prove that it is impossible to take all lines. For graph consisting of only one vertex it is obvious. Else fix some leaf. We must draw a line which are not directed to any neigbour because it is the only way to draw this line. But now we have tree with less number of vertices. So our statement is correct by induction.
Answer for tree is 2X + Y - 1.
So the problem now is just about building graph on points and checking each component on having cycles.
译:
首先,横纵坐标都不同的点集可以分开处理最后简单相乘。
考虑横坐标或者纵坐标相同的点集:
对于横坐标或者纵坐标相同的点,连一条边。
1.
形成一个环:
考虑最后的图像:先连接这个环,在环上的所有点都可以过这个点做不同于这条边方向的直线。
那么显然,设不同的横坐标有x个,不同的纵坐标有y个,那么这样的直线共有
x+y
条,任意直线都可删去,共有
2x+y
种不同图像。
2.
形成一颗树:
如果最后没有形成环,那么上图的最后两个点(B,C)显然不能简单的连接起来,对于最后一个点B只能做一条直线,也就是说除了横纵直线都有的情况,其他都可以做出,一共有
2x+y−1
种。
最后每种点集都乘起来就好了。
Code:
#include<iostream>
#include<vector>
#include<set>
#include<algorithm>
#include<cstdio>
using namespace std;
struct IO{
streambuf *ib,*ob;
inline void init(){
ios::sync_with_stdio(false);
cin.tie(NULL);cout.tie(NULL);
ib=cin.rdbuf();ob=cout.rdbuf();
}
inline int read(){
char ch=ib->sbumpc();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=ib->sbumpc();}
return i*f;
}
inline void W(int x){
static int buf[50];
if(!x){ob->sputc('0');return;}
if(x<0){ob->sputc('-');x=-x;}
while(x){buf[++buf[0]]=x%10;x/=10;}
while(buf[0]){ob->sputc(buf[buf[0]--]+'0');}
}
}io;
const int Maxn=1e5+50;
const int Mod=1e9+7;
typedef pair<int,int> pii;
int n,Xcoord[Maxn],Ycoord[Maxn],sum_degree,sum_point,vis[Maxn];
vector<int>Xcoords,Ycoords;
vector<pii>Line[Maxn],Row[Maxn];
vector<int>edge[Maxn];
set<int>diff_Xcoord;
set<int>diff_Ycoord;
inline void dfs(int now){
vis[now]=1;
sum_point++;sum_degree+=edge[now].size();
diff_Xcoord.insert(Xcoord[now]);
diff_Ycoord.insert(Ycoord[now]);
for(int e=edge[now].size()-1;e>=0;e--){
int v=edge[now][e];
if(vis[v])continue;
dfs(v);
}
}
inline int power(int a,int b){
int res=1;
for(;b;b>>=1,a=1ll*a*a%Mod)
if(b&1)res=1ll*res*a%Mod;
return res;
}
int main(){
//freopen("lx.in","r",stdin);
io.init();
n=io.read();
for(int i=1;i<=n;i++){
Xcoord[i]=io.read(),Ycoord[i]=io.read();
Xcoords.push_back(Xcoord[i]);Ycoords.push_back(Ycoord[i]);
}
sort(Xcoords.begin(),Xcoords.end());
sort(Ycoords.begin(),Ycoords.end());
for(int i=1;i<=n;i++){
Xcoord[i]=lower_bound(Xcoords.begin(),Xcoords.end(),Xcoord[i])-Xcoords.begin();
Ycoord[i]=lower_bound(Ycoords.begin(),Ycoords.end(),Ycoord[i])-Ycoords.begin();
}
for(int i=1;i<=n;i++){
Line[Xcoord[i]].push_back(make_pair(Ycoord[i],i));
Row[Ycoord[i]].push_back(make_pair(Xcoord[i],i));
}
for(int i=0;i<n;i++){
if(Line[i].size()){
sort(Line[i].begin(),Line[i].end());
for(int e=1;e<Line[i].size();e++){
int a=Line[i][e-1].second,b=Line[i][e].second;
edge[a].push_back(b);
edge[b].push_back(a);
}
}
if(Row[i].size()){
sort(Row[i].begin(),Row[i].end());
for(int e=1;e<Row[i].size();e++){
int a=Row[i][e-1].second,b=Row[i][e].second;
edge[a].push_back(b);
edge[b].push_back(a);
}
}
}
static int ans=1;
for(int i=1;i<=n;i++){
if(vis[i])continue;
dfs(i);
int k=power(2,diff_Xcoord.size()+diff_Ycoord.size());
if(sum_degree==2*sum_point-2)k=(k+Mod-1)%Mod;
ans=1ll*ans*k%Mod;
sum_degree=0,sum_point=0;
diff_Xcoord.clear();diff_Ycoord.clear();
}
io.W(ans);
}