HDU 2473 Junk-Mail Filter

/*
转载自 ______________白白の屋  
*/
#include <iostream>
#include <algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
int set[1350005];
int a[125000];
int N,M;
int inline find ( int x )
{
    return x != set[x] ? set[x] = find ( set[x] ) : set[x];
}
void inline merge ( int x, int y )
{
     x = find ( x );
     y = find ( y );
     if ( x == y )  return ;
     set[x] = y;
}
int main ()
{
    int ca = 1;
    while ( scanf ( "%d%d",&N,&M ), M || N )
    {
            for ( int i = 0; i < N; ++ i )
                  set[i] = i+N;
            for ( int i = N; i <= N + N + M; ++ i )
                  set[i] = i;          /*  这是关键, 虽然空间的消耗比较大, 但
                                            是节省了大量时间, 这样处理的目的是将
                                            0 -> N-1 的 节点处理成叶子节点

                                            这样在对这些 节点做 S 操作的时候就
                                            不会影响到其他的节点, 而 find 操作
                                            是带路径压缩的, 所以就保证了我们所
                                            有要处理的节点一直是叶子节点 !!!*/
            int sep = N + N;
            int x,y; char ch[5];
            for ( int i = 0; i != M; ++ i )
            {
                  scanf ( "%s",ch );
                  switch ( ch[0] )
                  {
                           case 'M': scanf ( "%d%d",&x,&y ); merge ( x,y ); break;
                           case 'S': scanf ( "%d",&x ); set[x] = sep ++;    break;          //初始化操作就是为这一步准备的
                  }
            }
            for ( int i = 0; i != N; ++ i )
                  a[i] = find ( i );
            sort ( a, a + N );
            int nCount = 1;
            for ( int i = 1; i < N; ++ i )
                  if ( a[i] != a[i-1] ) nCount ++;
            printf("Case #%d: %d\n",ca++,nCount);
    }
    return 0;
}


这是一题并查集的结合和借点删除的题目,

网上查的资料主要是设置一个虚拟映射数组,来存放要删除的节点,每次对虚拟映射

数组操作,不影响原来的数组,以下贴的代码转自  ______________白白の屋 

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

你可能感兴趣的:(filter,merge)