CF1012B 化学桌
1 CF1012B 化学桌
2 题目介绍
时间限制 \(1s\) | 空间限制 \(512M\)
\(Innopolis\) 大学的科学家继续调查元素周期表。已知元素有 \(n·m\) 个,它们形成一个周期表:一个具有 \(n\) 行和 \(m\) 列的矩形。每个元素都可以通过表格中的坐标 \((r,c)(1≤r≤n,1≤c≤m)\) 描述。
最近,科学家发现,此表中每四个不同的元素形成一个矩形,且矩形的边与表的边平行,如果它们具有这四个元素中的三个的样本,则可以使用核聚变生成第四个元素的样本。因此,如果我们在位置 \((r1,c1),(r1,c2),(r2,c1)\) 中有元素,其中 \(r1≠r2\) 和 \(c1≠c2\) 那么我们可以生成元素 \((r2,c2)\)。
核聚变中使用的样品不会浪费,可以在以后的核聚变中再次使用。新制作的元素也可以在将来的核聚变中使用。
\(Innopolis\) 大学的科学家已经拥有 \(q\) 元素的样本。他们想要获得所有 \(n·m\) 个元素的样本。为此他们将从其他实验室购买一些样品,然后使用任意数量的核聚变以某种顺序生产所有剩余的元素。帮助他们找到需要购买的最少数量的元素。
3 题解
我们分析题目,发现:对于存在的三个点 \((x_1, y_1), (x_1, y_2), (x_2, y_1)\),点 \((x_2, y_2)\) 自动上色。我们观察这三个点:每个点都可以看作是一对横纵坐标的关系,而这三个点正好间接形成了一对 \(x_2\) 和 \(y_2\) 的关系。因此,我们可以想到用并查集维护横坐标和纵坐标,每增加一个点就将这个点对应的横纵坐标加入同一集合中。当我们结束所有操作之后,如果剩下的集合数不为 \(1\),那么说明图上有一些点没有染色。此时,再在这些集合中任意选取一些节点连接,使得总集合个数变成 \(1\)。设集合数为 \(cnt\),那么答案就是 \(cnt - 1\)。注意这里我们给所有的纵坐标都加上一个 \(n\),便于和横坐标区分。
下面我给出做法正确性的具体证明:对于集合中的任意两个元素,如果他们之间直接有连接,那么该位置一定有一个上色的点。如果不直接连接,那么追根溯源一定能找到两个直接连接的元素,假如这两个元素又分别连着两个不同元素,那么这四个元素之间自动连接。这两个元素连接的两个不同元素就可以视作连接在了一起,这样一层一层递推,最终就可以给当前这个点上色。
4 代码(空格警告):
#include <iostream>
using namespace std;
const int N = 4e5+10;
int n, m, q, cnt;
int fa[N];
int u, v;
int find(int x)
{
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
int main()
{
cin >> n >> m >> q;
for (int i = 1; i <= n+m; i++) fa[i] = i;
for (int i = 1; i <= q; i++)
{
cin >> u >> v;
int x = find(u), y = find(v+n);
if (x == y) continue;
fa[x] = y;
}
for (int i = 1; i <= n+m; i++) if (fa[i] == i) cnt++;
cout << cnt-1;
return 0;
}