矩形填補
問題描述
給定平面
輸入格式
第一行一個整數
輸出格式
一個整數,表示最後有多少個點
輸入1
3
1 1
1 2
2 2
輸出1
4
輸入2
5
0 0
1 0
0 1
1 2
2 1
輸出2
9
Solution
首先我們把縱座標相同的點合併成一條線。
注意到,有橫座標相同的點的兩條線或矩形 可構成的最大矩形中的每個點都可以被染色。
所以,我們把 有橫座標相同的點的兩條線或矩形 能構成的最大矩形的邊長求出來,然後逐個考慮即可。
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#define Max(x,y) ((x)>(y)?(x):(y))
#define Min(x,y) ((x)<(y)?(x):(y))
#define LL long long
using namespace std;
LL n,ans,tt[200010],h[200010],fa[200010],xx[200010],yy[200010];
bool vis[200010];
struct P{LL x,y,z;}p[200010];
LL find(LL x){
LL tmp=x,pre;
while(tmp!=fa[tmp])tmp=fa[tmp];
while(x!=tmp)pre=fa[x],fa[x]=tmp,x=pre;
return tmp;
}
void merge(LL x,LL y){
LL fx=find(x),fy=find(y);
if(fx==fy){
tt[fx]--;
return;
}
fa[fy]=fx;
if(yy[fx]==yy[fy])tt[fx]+=tt[fy];
else{
h[fx]+=h[fy];
tt[fx]+=tt[fy]-1;
}
}
bool cmp1(P x,P y){
return ((x.y<y.y)||(x.y==y.y&&x.x<y.x));
}
bool cmp2(P x,P y){
return ((x.x<y.x)||(x.x==y.x&&x.y<y.y));
}
inline void in(LL &x){
x=0;char ch=getchar();LL flag=1;
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-'){flag=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
x*=flag;
}
int main(){
freopen("filling.in","r",stdin);
#ifndef DEBUG
freopen("filling.out","w",stdout);
#endif
in(n);
for(LL i=1;i<=n;i++)in(p[i].x),in(p[i].y),p[i].z=i,xx[i]=p[i].x,yy[i]=p[i].y,fa[i]=i,h[i]=1,tt[i]=1;
sort(p+1,p+n+1,cmp1);
for(LL i=1,it;i<=n;i=it){
LL pre=p[i].y;it=i+1;
while(p[it].y==pre&&it<=n){
merge(p[i].z,p[it].z);
it++;
}
}
sort(p+1,p+n+1,cmp2);
for(LL i=1,it;i<=n;i=it){
LL pre=p[i].x;it=i+1;
while(p[it].x==pre&&it<=n){
merge(p[i].z,p[it].z);
it++;
}
}
for(LL i=1;i<=n;i++){
LL x=find(i);
if(vis[x])continue;
vis[x]=true;
ans+=tt[x]*h[x];
}
printf("%lld\n",ans);
return 0;
}