N - Dragon Balls(并查集+深度的意义

有标号为1到n的n个龙珠,分别放在对应标号为1到n的n个城市里。
下面有两种操作:
T A B表示把A龙珠所在城市的所有龙珠都转移到B龙珠所在的城市中
Q A 表示查询A,需要知道A龙珠现在所在的城市,A所在的城市有几颗龙珠,A转移到这个城市移动了多少次,分别输出3个整数,表示上述信息。 

前两个用普通并查集就能算出来,移动次数不好维护;

如果我们不进行路径压缩,那么查询点的深度即是移动的次数,因为每移动一次父节点就下降一层,深度+1;

但不路径压缩的话就会超时,所以我们要把点的深度记录下来;;

#include <cstdio>
#include <algorithm>
#include <iostream>

using namespace std;
int  ans[100000] ,ansn[100000] ,pre[100000];

void init( int x){
    for( int i = 0 ; i<=x ;i++){
        pre[i] = i;
        ans[i] = 0;
        ansn[i] = 1;
    }
}

int  find( int a){
   /* int r=a;           //刚开始这样记录深度ans[a],但是这样不对,这样只是路径压缩一次ans[n]++,但实际上一次可能压缩很多层,所以应该是加上上一层的压缩层数
    while( pre[a]!=a){
        a=pre[a];
     }
     int t;
     while( pre[r]!=a){
         ans[r]++;
         t= pre[r];
         pre[r] =a;
         r=t;
     }*/
     if( a == pre[a] )return a;
     else{
        int tmp= pre[a];
        pre[a] = find( pre[a]);
        ans[a] += ans[tmp];
     }
     return pre[a];
}

int add( int a ,int b){
     int x=find(a);
     int y=find(b);
     if( x != y){
         pre[x] = y;
         ans[x] = 1;
         ansn[y] += ansn[x];
         ansn[x] =0;
     }
}

int main( ){
     int ks=0, T;
     scanf("%d",&T);
     while( T--){
         printf("Case %d:\n",++ks);
        int n,m;
        scanf("%d%d" ,&n ,&m);
        init( n);
        while( m--){
             char op[10];
             int a,b;
             scanf("%s",op);
             if( op[0] == 'T'){
                scanf("%d%d" ,&a,&b);
                add( a,b);
             }
             if( op[0] == 'Q'){
                 scanf("%d" ,&a);
                 int b=find(a);
                     printf("%d %d %d\n" ,b ,ansn[b] ,ans[a]);
             }
        }
     }
    return 0;
}
posted @ 2019-04-06 13:56  易如鱼  阅读(494)  评论(0编辑  收藏  举报