UVA 11987

受教了,感谢玉斌大神的博客。

这道题最难的地方就是操作2,将一个集合中的一个点单独移到另一个集合,因为并查集的性质,如果该点本身作为root节点的话,怎么保证其他点不受影响。

玉斌大神的思路很厉害,受教受教,即,由于题目最终输出集合的元素个数与权值总和,故添加一个delete操作,将该点(设为P)所在集合的rank和sum值减小,将p的father引向一个从没定义过的点,(可以设置为(总数++)点),这样,虽然看似P还留在原集合,但仅仅作为一个空骨架,并不对集合的rank和sum产生影响。

具体实现,需要借助一个辅助数组 id[], id[]初始和father[]相同,但一旦需要删除操作,即将id[p]=++n,指向一个新位置,下次father[id[x]]即指向了新位置,跟原集合无关了。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int father[200005]; //由于最坏可能有1000000次删除操作,故最大的数组量
int rank[200005];
long long sum[200005];
int id[200005];
int n;
int cnt;
void init()
{
    for(int i=1;i<=n;i++)
    {
        father[i]=i;
        rank[i]=1;
        sum[i]=i;
        id[i]=i;
    }
    cnt=n;
}
int findset(int x)
{
    if (x!=father[x])
    {
        father[x]=findset(father[x]);
    }
    return father[x];
}
void unionset(int x,int y)
{
    x=id[x];
    y=id[y]; //所有点的指向,全部通过一个间接的id[x]的值来指向相应的值 即将所有点全部id化,不再已原来的本身值为id。
    int r1=findset(x);
    int r2=findset(y);
    if (r1==r2) return;
    if (rank[r1]>rank[r2])
    {
        father[r2]=r1;
        rank[r1]+=rank[r2];
        sum[r1]+=sum[r2];
    }
    else
    {
        father[r1]=r2;
        rank[r2]+=rank[r1];
        sum[r2]+=sum[r1];
    }
}
void q1()
{
    int p,q;
    scanf("%d %d",&p,&q);
    unionset(p,q);
}
void dele(int x)
{
    int r=findset(id[x]);
    rank[r]--;
    sum[r]-=x;
    id[x]=++cnt;
    father[id[x]]=id[x];
    rank[id[x]]=1;
    sum[id[x]]=x;
}
void q2()
{
    int p,q;
    scanf("%d %d",&p,&q);
int    r1=findset(id[p]);
int    r2=findset(id[q]);
    if (r1==r2) return;
    dele(p);
    unionset(p,q);
}
void q3()
{
    int p;
    scanf("%d",&p);
    int root=findset(id[p]);
    printf("%d %lld
",rank[root],sum[root]);
}
int main()
{
    int q;
    while (scanf("%d %d",&n,&q)!=EOF)
    {
        init();
        int i,j,k;
        for (i=1;i<=q;i++)
        {
            int deno;
            scanf("%d",&deno);
            if (deno==1) q1();
            if (deno==2) q2();
            if (deno==3) q3();
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kkrisen/p/3250142.html