思路: 并查集
分析:
1 题目说有n个城市每一个城市有一个龙珠编号为i,现在有m行的输入包括两种的情况
T x y 把x所在的集合的所以龙珠转移到y集合上 Q x 询问x所在集合的龙珠的个数
2 我们利用rank[x]表示的是根节点为x的集合的元素的个数,但是现在我们发现求转移的次数不好求,刚开始我用的是一个vector数组来保存,比如v[x]表示以x为根节点的集合的元素,那么如果是把fx这个集合并到fy上的话,那么我们枚举v[fx]。但是这个方法TLE了
3 后来看了网上的题解,发现在求转移次数的时候我们也可以利用递归合并的思想,比如把fx所在的集合转移到fy的时候,那么我们只要把fx的转移次数加一,那么下次递归的时候我们在里面进行处理即可
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int MAXN = 10010; int n , m; int father[MAXN]; int rank[MAXN]; int num[MAXN]; void init(){ memset(num , 0 , sizeof(num)); for(int i = 0 ; i <= n ; i++){ father[i] = i; rank[i] = 1; } } int find(int x){ if(father[x] != x){ int fa = father[x]; father[x] = find(fa); rank[x] += rank[fa]; num[x] += num[fa]; } return father[x]; } void Union(int x , int y){ int fx = find(x); int fy = find(y); if(fx != fy){ father[fx] = fy; rank[fy] += rank[fx]; num[fx]++; } } void solve(int x){ int fx = find(x); printf("%d %d %d\n" , fx , rank[fx] , num[x]); } int main(){ int cas , Case = 1; char c; int x , y; scanf("%d" , &cas); while(cas--){ scanf("%d%d%*c" , &n , &m); init(); printf("Case %d:\n" , Case++); while(m--){ c = getchar(); if(c == 'T'){ scanf("%d%d%*c" , &x , &y); Union(x , y); } else{ scanf("%d%*c" , &x); solve(x); } } } return 0; }