POJ 1988

#include<stdio.h>

#include<string.h>

int bot[30005];//以每个集合最底下的那个立方体作为根节点,初始化为自己本身

int sum[30005];//表示以该元素为父亲节点的元素的编号的增量

int cisum[30005];//根节点所在集合的立方体总数

int num[30005];//记录每个节点在其父亲节点的集合内的编号,注意是其父亲节点而不一定是根节点

int findbot(int a)//找到根节点并且压缩路径

{

    int zsum=0,j;

    int tmp=a;

    while(a!=bot[a])//找到根节点,并且计算一路来所有是别人父亲元素的sum和

    {

        a=bot[a];

        zsum+=sum[a];

    }

    while(tmp!=bot[tmp])//压缩路径

    {

        num[tmp]+=zsum;//将num数组加上以后所有父亲节点的sum

        sum[tmp]+=zsum;//更新本身作为别人父亲节点的sum

        j=tmp;

        tmp=bot[tmp];

        zsum-=sum[tmp];//减掉自己本身的sum因为自己本身的sum与自己已经没有关系,注意sum是作为别人的父亲别人应该加上的数目

        bot[j]=a;

    }

    return a;

}

void link(int a,int b)

{

    int tmpa,tmpb;

    tmpa=findbot(a);

    tmpb=findbot(b);

    bot[tmpa]=tmpb;

    num[tmpa]+=cisum[tmpb];

    sum[tmpa]=cisum[tmpb];

    cisum[tmpb]+=cisum[tmpa];

}

int main()

{

    int n,a,b;

    char ca;

    scanf("%d",&n);

    {

        memset(sum,0,sizeof(sum));

        for(int i=1;i<=30001;i++)

        {

            bot[i]=i;

            cisum[i]=num[i]=1;

        }

        for(int i=0;i<n;i++)

        {

            getchar();

            scanf("%c",&ca);

            if(ca=='M')

            {

                scanf("%d%d",&a,&b);

                link(a,b);

            }

            else if(ca=='C')

            {

                scanf("%d",&a);

                findbot(a);

                printf("%d\n",num[a]-1);

            }

        }

    }

    return 0;

}

 

你可能感兴趣的:(poj)