题目链接:http://codeforces.com/problemset/problem/1012/B
题目大意:
有一个n*m的矩阵, 初始时有q个点, 对于任意一个面积不为0的矩形来说, 如果具备其中三个顶点, 则可以产生剩下的第四点, 求最少补充多少个点能够生成所有这n*m个点。
(n,m≤2∗105,q≤min(n∗m,2∗105))
(
n
,
m
≤
2
∗
10
5
,
q
≤
m
i
n
(
n
∗
m
,
2
∗
10
5
)
)
题目思路:
考虑一个二分图, 左边n个点, 右边m个点, 对于原来的点(x,y), 可以看作x->y的边。 考虑一条路径x->y, 如果x,y直接相连, 说明原来就有点, 无须添加, 否则, 根据二分图的性质, 一定是条长度>=3的为奇数的交错路径, 而考虑前三个点x->a->b, 根据定义, 可以生成x->b这条边, 故交错路径长度-2, 一直做下去, 会直接产生x->y这条边。 故对于一个联通块而言, 其中的所有点都可以产生出来。
所以答案就是联通分量数-1。
Code:
#include <map>
#include <set>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define id(x, y) ((x - 1) * m + y)
using namespace std;
const int N = (int)4e5 + 10;
int n, m, q, fa[N];
int find(int x){
if (x != fa[x]) return fa[x] = find(fa[x]);
return x;
}
void unit(int r1, int r2){
r1 = find(r1), r2 = find(r2);
if (r1 != r2) fa[r2] = r1;
}
int main(){
scanf("%d %d %d", &n, &m, &q);
for (int i = 1; i <= n + m; i ++)
fa[i] = i;
while (q --){
int i, j;
scanf("%d %d", &i, &j);
unit(i, n + j);
}
int ans = 0;
for (int i = 1; i <= n + m; i ++)
if (find(i) == i) ans ++;
printf("%d", ans - 1);
return 0;
}