HDU 2473 Junk-Mail Filter(并查集)

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2473

 

题意:有0到n-1个数,M a b  表示a和b合并,S a表示删除a,删除以后a变成独立的集合。。。最后问共有几个集合。。。。

 

开始做的时候是真的按步就搬地把a删除,然后把他儿子和他老爸都合起来。。。结果超时。。。。

还有吧本来是int 型的a,b写成了 char型导致一直溢出,找了很久才找到。。。

 

 

这里用了代理index[i]表示i的代理是index[i],然后以后操作的时候每个人干活只找代理干,然后删除的时候直接换个新代理(这个代理不能和别人的代理冲突,开始的时候是独立的集合),

然后他原来的代理事实上还在本来那里,没有删除,因为我们只找代理来干活,而他原来的代理已经不是代理了,所以不会找到原来那个代理。。。。。

 

最后统计的时候,正常来说我们可以扫一遍代理,看father[代理] == 代理就累加,而这里不正常,会计少了集合的。。。。。

因为当你删除的代理是根,而该树的儿子孙子还有别人的代理,即该集合也算一个集合,当你最后找的时候,因为只找代理,而那些算一个集合的,而根本来是代理,因为删除后而不是代理了的集合就会没有统计。。。。

 

所以我们扫所有代理用Find()来找根,然后用标记法(因为可能多个代理同一个根)来把根标记,最后统计根的个数

 

 

#include <iostream>

using namespace std;



const  int M = 10000100;



int father[M];

int rank1[M];

int save[M];

int index[M];

bool used[M];





void Make_Set(int x)

{

    father[x] = x;

    rank1[x] = 0;

}



int Find(int x)

{

    int k = 0;

    while (x != father[x])

    {

        save[k++] = x;

        x = father[x];

    }



    for (int j = 0; j < k; j++)

    {

        father[save[j]] = x;

    }

    return x;

}





void Union(int a, int b)

{



    int x = Find(a);

    int y = Find(b);

    

    if (x == y)

    {

        return;

    }

    if (rank1[x] < rank1[y])

    {

        father[x] = y;

    }

    else

    {

        father[y] = x;

        if (rank1[x] == rank1[y])

        {

            rank1[x]++;

        }

    }

}







int main()

{

    int n, m;

    int case1 = 0;

    while (~scanf("%d%d", &n, &m), n + m)

    {

        

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

        {

            Make_Set(i);

            index[i] = i;//开始代理都是本身

        }



        int k = n+1;

        while (m--)

        {

            char str[10];

            int a, b;

            scanf("%s", str);

            if (str[0] == 'M')

            {

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

                Union(index[a], index[b]);

            }

            else

            {

                scanf("%d", &a);

                index[a] = k++;//换代理

                Make_Set(index[a]);

            }



        }



        int count = 0;

        memset(used, 0, sizeof(used));

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

        {

            //if (father[i] == i)或father[index[i]] == index[i] 都是错的

            //{

            //    count++;

            //}

            used[Find(index[i])] = 1;//标记根

        }



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

        {

            if (used[i])

            {

                count++;

            }

        }



        printf("Case #%d: %d\n", ++case1, count);

    }

    return 0;

}

 

你可能感兴趣的:(filter)