中文大意:

日本总共有 n 颗龙珠,被神龙放置在了 n 个城市中。

T A B :将龙珠 A 所在城市中的所有龙珠运送到龙珠 B 的所在城市。假定这两个城市是不同的。

Q A   :输出龙珠 X 所在的城市,该市中龙珠的个数以及龙珠 X 的运输次数。 

 

思路:

一个城市就是一个集合,龙珠就是集合中的节点。

本题的难点在于,如何更新每个龙珠的移动次数。

在合并操作中,times[x]++; 只是更新了原根节点的移动次数。而非根节点的移动次数并未更新。

非根节点的移动次数 = 当前节点的移动次数 + 原根节点的移动次数 + ... 

这个过程,需要利用迭代操作来实现,请结合下面例子自行体会:

4

T 1 2

T 2 3

T 3 4

Q 1

 

代码:

#include<iostream>using namespace std;int n,q;int city[10001];//各龙珠所在城市 int times[10001];//各龙珠的移动次数 int cnt[10001];//各城市的龙珠个数 void init(){for(int i=1;i<=n;i++){
        city[i] = i;
        times[i] = 0;
        cnt[i] = 1;
    }
}//寻找龙珠 x 的所在城市 int find(int x){if(city[x] == x){return x;
    }int root = find(city[x]);//当前龙珠的移动次数 = 当前龙珠移动次数 + 根节点龙珠移动次数 times[x] += times[city[x]];
    city[x] = root;return root;
}//合并 void union_set(int x, int y){
    x = find(x);
    y = find(y);
    
    city[x] = y;
    times[x]++;
    cnt[y] += cnt[x];
}int main(){int t;
    scanf("%d", &t);for(int k=1;k<=t;k++){
        scanf("%d %d", &n, &q);
        init();
        printf("Case %d:\n",k);        char c;int x,y;for(int i=0;i<q;i++){
            getchar(); 
            scanf("%c", &c);            if(c == 'T'){
                scanf("%d %d", &x, &y);
                union_set(x, y);
            }else if(c == 'Q'){
                scanf("%d", &x);int root = find(x);
                printf("%d %d %d\n", root, cnt[root], times[x]);
            }
        }
    }
}