题意:有个n * m的元素周期表,如果我们有元素在(r1, c1), (r1, c2), (r2, c1),那们我们可以产生(r2, c2)元素。
给定q个元素的坐标,求最少放置多少个元素,使得棋盘上拥有n * m个元素。

分析:左边是n个行号,右边是m个列号,我们产生的每个元素都是一个行号和一个列号连边,我们要使得这个二分图变成完全二分图,
即总共有n * m条边。我们只需要将每个独立的连通块合并到一个集合,那么就是答案,合并的操作次数是连通块个数减1。
重点:我们要把所有的连通块合并到一个集合。这是化学反应产生的结果。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 400005;
int p[N];

int find(int x)
{
	if (p[x] != x) p[x] = find(p[x]);
	return p[x];
}

int main()
{
	int n, m, q;
	scanf("%d%d%d", &n, &m, &q);

	for (int i = 1; i <= n + m; ++i) p[i] = i;

	int r, c;
	for (int i = 1; i <= q; ++i)
	{
		scanf("%d%d", &r, &c);
		c += n;
		p[find(r)] = find(c);
	}

	int res = 0;
	for (int i = 1; i <= n + m; ++i)
	{
		if (p[i] == i)
			++res;
	}

	printf("%d\n", res - 1);


	return 0;
}