F - Must Be Rectangular!
Time Limit: 2 sec / Memory Limit: 1024 MB
Score :
600
points
Problem Statement
There are
N
dots in a two-dimensional plane. The coordinates of the i-th dot are ((x_i,y_i)).
We will repeat the following operation as long as possible:
Choose four integers a, b, c, d (a
≠
c
,
b
≠
d
)
such that there are dots at exactly three of the positions
(
a
,
b
)
,
(
a
,
d
)
,
(
c
,
b
)
and
(
c
,
d
)
, and add a dot at the remaining position.
We can prove that we can only do this operation a finite number of times. Find the maximum number of times we can do the operation.
Constraints
- 1≤N≤(10^5)
....
详见题目链接
思路
将每一个点拆成两个点即横纵各一点
然后将该两点连线
好处
自然将横坐标相等或纵坐标相等的若干点构成一个联通块
如
是由(0,1),(1,1),(1,2),(1,0),(2,2)通过以上方法构成的
统一将纵坐标加上一个10的目的是避免x,y不能相互区分
然后 这样做了有什么用吗?
答案是肯定的
用并查集来维护
for(i = 1;i <= n;i++)
{
int u,v;
//u-x,v-y
scanf("%d%d",&u,&v);
f[FindSet(u)] = FindSet(v + MAXN);
}
再设数组difx[]
和dify[]
dif即difference用来统计横坐标或纵坐标的不同数的多少
因为单纯点数 可能在行或列上有重合
for(i = 1;i <= MAXN;i++)
difx[FindSet(i)]++;
for(i = MAXN + 1;i <= MAXN * 2;i++)
dify[FindSet(i)]++;
1(0,1)
2(1,1)
3(1,0)
4(1,2)
5(2,2)
如图 的话 横坐标或纵坐标的不同数的多少各为3
乘起来为整个矩阵点数 再减去已有的 就是答案
但考虑到 可能不止一个联通块 所以需要一个枚举的操作
for(i = 1;i <= MAXN * 2;i++)
ans += 1ll * difx[i] * dify[i];
但聪明的同学可能会想到
如果那些构不成(横或纵相等的在3个以下)的被误算了怎么办
for(i = 1;i <= MAXN;i++)
difx[FindSet(i)]++;
for(i = MAXN + 1;i <= MAXN * 2;i++)
dify[FindSet(i)]++;
先前的代码 是加在祖先上的
如果只有一个点(该点所在的行和列无它点)第一个FindSet(i) = 该点的纵坐标加MAXN
可见只加了1 和 后面的减n是抵消了的
然后 又会有同学提到 并查集的初始化
for(i = 1;i <= MAXN * 2;i++) f[i] = i;
公平地给所有赋了值 包括一些实际上不存在的点
那么是否有可能再次造成误算呢?
这位同学 您又错了
因为对于一个不存在的i
difx[FindSet(i)]++;即difx[i]++;
而ans加时加的是difx[FindSet(i)]*dify[FindSet(i)]
细节
difx的i和dify的i是错开枚举的
即difx[i]>0定有dify[i]
反之亦然
所以不会干扰结果
代码
#include <cstdio>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 100000,MAX = 200005;
int f[MAX],difx[MAX],dify[MAX];
inline int FindSet(int a)
{
if(a == f[a]) return a;
return f[a] = FindSet(f[a]);
}
int main()
{
int i,n;
scanf("%d",&n);
for(i = 1;i <= MAXN * 2;i++) f[i] = i;
for(i = 1;i <= n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
f[FindSet(u)] = FindSet(v + MAXN);
//不能写成f[FindSet(u)] = v + MAXN;
//否则会RE我也不知道为什么QAQ
}
for(i = 1;i <= MAXN;i++)
difx[FindSet(i)]++;
for(i = MAXN + 1;i <= MAXN * 2;i++)
dify[FindSet(i)]++;
long long ans = 0;
for(i = 1;i <= MAXN * 2;i++)
ans += 1ll * difx[i] * dify[i];
printf("%lld",ans - n);
return 0;
}