您的位置:首页 > 产品设计 > UI/UE

Building Block(并查集)

2015-09-06 10:25 501 查看
该题是个比较明显的并查集题目,只不过需要求的不是一个集合中元素的个数,而是某个数下面的积木个数。

显然,我们需要维护一些量,来达到计算的目的。 为了使得并查集高效,我们显然不能放弃了路径压缩,那样会导致并查集退化成一条长长的链,效率十分低下。

但是我们可以注意到,由于路径压缩的缘故,每次遍历到的点都会被直接连到祖先结点上。那么我们可以维护一个under数组,以under[i]表示结点i之下有多少积木。

但是这样会有一个问题,在合并操作之后怎么搬? 我们可以发现,对于每一堆积木,个数只会增加不会减少,所以under[i]也只会增加不可能减少,所以我们不妨再维护每个集合里的元素个数,将这个量维护在根结点上,每次合并的时候只需要更新移动的那堆积木根结点i的under[i],以及集合元素个数。

该题需要对并查集的原理非常熟悉,望读者好好体会。

细节参见代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
typedef long long ll;
const int INF = 1000000000;
const int maxn = 30000 + 5;
int n,q,m,a,b,p[maxn],cnt[maxn],under[maxn];
void init() {
    for(int i=0;i<maxn;i++) {
        p[i] = i;
        cnt[i] = 1;
        under[i] = 0;
    }
}
int setfind(int x) {
    if(p[x] == x) return x;
    else {
        int root = setfind(p[x]);
        under[x] += under[p[x]];
        return p[x] = root;
    }
}
char s[5];
int main() {
    while(~scanf("%d",&q)) {
        init();
        while(q--) {
            scanf("%s",s);
            if(s[0] == 'M') {
                scanf("%d%d",&a,&b);
                int x = setfind(a), y = setfind(b);
                if(x != y) {
                    p[x] = y;
                    under[x] = cnt[y];
                    cnt[y] = cnt[x] = cnt[x]+cnt[y];
                }
            }
            else {
                scanf("%d",&a);
                int x = setfind(a);
                printf("%d\n",under[a]);
            }
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: