Chemical table CFR500 div2D(并查集)

给定的一个n*m的区域内,给出一些点的坐标,这些点上有一个元素,如果在矩形的子矩形的三个点都有元素,那么第四个点的元素可以自己产生,其他的元素需要购买,问最少需要购买多少中元素才可以把这个区域给填满。

对于给出点的,先用并查集把x轴上和y轴上有联系的点都联系起来,并且可以顺便把出现过的x和y的数值标记起来。

如果我把所有的点分成了n块,那么的需要添加n-1个元素来把这n块连接起来。对于没有出现的x和y的数值,我需要额外买一个元素来填充这个点。

因为我已经在一个块内的点一定是有联系的,而另一个块的点一定与这里面的点都没有联系,所以我只需要添加一个元素让他们的 x 或者 y 联系起来,那么这个块一定可以形成一个包含三个点的子矩形,也就可以产生出另一个点的元素。就可以把这些块里出现的x和y的横纵方向填满,这样就会剩下那么没有出现的x和y位置上的点还是空的了,然后同样的也只需要添加一个就可以填满一行或者一列。

#include<map>
#include<set>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lowbit(x) (x & (-x))

typedef unsigned long long int ull;
typedef long long int ll;
const double pi = 4.0*atan(1.0);
const int inf = 0x3f3f3f3f;
const int maxn = 200005;
const int maxm = 1000005;
const int mod = 10007;
using namespace std;

int n, m, tol, T;
int fa[maxn];
int X[maxn];
int Y[maxn];

int find(int x) {
    return fa[x] == x ? x : fa[x] = find(fa[x]);
}

void build(int x, int y) {
    int u = find(x);
    int v = find(y);
    fa[v] = u;
}

int main() {
    int q;
    scanf("%d%d%d", &n, &m, &q);
    for(int i=1; i<=q; i++)    fa[i] = i;
    int x, y;
    for(int i=1; i<=q; i++) {
        scanf("%d%d", &x, &y);
        if(X[x])     build(i, X[x]);
        X[x] = fa[i];
        if(Y[y])    build(i, Y[y]);
        Y[y] = fa[i];
    }
    ll ans = -1;
    for(int i=1; i<=q; i++)
        find(i);
    for(int i=1; i<=q; i++)
        if(fa[i] == i)    ans++;
    for(int i=1; i<=n; i++)
        if(!X[i])    ans++;
    for(int i=1; i<=m; i++)
        if(!Y[i])    ans++;
    printf("%I64d
", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jiaaaaaaaqi/p/9396860.html