Problem Description
Five hundred years later, the number of dragon balls will increase unexpectedly, so it's too difficult for Monkey King(WuKong) to gather all of the dragon balls together.
His country has N cities and there are exactly N dragon balls in the world. At first, for the ith dragon ball, the sacred dragon will puts it in the ith city. Through long years, some cities' dragon ball(s) would be transported to other cities. To save physical strength WuKong plans to take Flying Nimbus Cloud, a magical flying cloud to gather dragon balls.
Every time WuKong will collect the information of one dragon ball, he will ask you the information of that ball. You must tell him which city the ball is located and how many dragon balls are there in that city, you also need to tell him how many times the ball has been transported so far.

His country has N cities and there are exactly N dragon balls in the world. At first, for the ith dragon ball, the sacred dragon will puts it in the ith city. Through long years, some cities' dragon ball(s) would be transported to other cities. To save physical strength WuKong plans to take Flying Nimbus Cloud, a magical flying cloud to gather dragon balls.
Every time WuKong will collect the information of one dragon ball, he will ask you the information of that ball. You must tell him which city the ball is located and how many dragon balls are there in that city, you also need to tell him how many times the ball has been transported so far.
Input
The first line of the input is a single positive integer T(0 < T <= 100).
For each case, the first line contains two integers: N and Q (2 < N <= 10000 , 2 < Q <= 10000).
Each of the following Q lines contains either a fact or a question as the follow format:
T A B : All the dragon balls which are in the same city with A have been transported to the city the Bth ball in. You can assume that the two cities are different.
Q A : WuKong want to know X (the id of the city Ath ball is in), Y (the count of balls in Xth city) and Z (the tranporting times of the Ath ball). (1 <= A, B <= N)
For each case, the first line contains two integers: N and Q (2 < N <= 10000 , 2 < Q <= 10000).
Each of the following Q lines contains either a fact or a question as the follow format:
T A B : All the dragon balls which are in the same city with A have been transported to the city the Bth ball in. You can assume that the two cities are different.
Q A : WuKong want to know X (the id of the city Ath ball is in), Y (the count of balls in Xth city) and Z (the tranporting times of the Ath ball). (1 <= A, B <= N)
Output
For each test case, output the test case number formated as sample output. Then for each query, output a line with three integers X Y Z saparated by a blank space.
Sample Input
2 3 3 T 1 2 T 3 2 Q 2 3 4 T 1 2 Q 1 T 1 3 Q 1
Sample Output
Case 1: 2 3 0 Case 2: 2 2 1 3 3 2
解题思路:
该题大意是有n个龙珠在n个城市,现分别执行以下两种操作:“T”表示将x龙珠移到y城市,而“Q”表示输出x所在城市,该城市的龙珠总数,以及该龙珠移动次数。
此题就是一道纯并查集的简单应用,但却涉及到了路径压缩的知识。下面先来介绍一下路径压缩。
关于路径压缩,维基百科解释如下:
“路径压缩”,是一种在执行“查找”时扁平化树结构的方法。关键在于在路径上的每个节点都可以直接连接到根上;他们都有同样
的表示方法。为了达到这样的效果,Find
递归地经过树,改变每一个节点的引用到根节点。得到的树将更加扁平,为以后直接或者
间接引用节点的操作加速
那什么是扁平化呢?
其实就是减少了树的深度,使得下一次查找更加方便。
下面是迭代版路径压缩:
int findRoot(int x)
{
int tempRoot;
int root = x;
while(root != parent[root])
root = parent[root];
while(x != root)
{
tempRoot = parent[x];
parent[x] = root;
x = tempRoot;
}
return root;
}
但有时候有些题却不能用迭代版,于是有下面的递归版:
int find_root(int x)
{
int root;
root = x;
while( root != father[root])
root = father[root];
return root;
}
再回到问题上来,前面2个很好实现,最后移动次数有点麻烦,将要转移的龙珠所在城市的根节点的转移次数加1,等到路径压缩时,子节点自己移动次数加上根节点移动次数,就是节点总共移动次数。
可能有点绕,稍微从文字角度上说一下。
比如说要把城市i的龙珠转移到j,先让i所在树的根(这里的根其实就是i城市本来有的龙珠也就是i号龙珠)的转移次数为1(因为第一次转移)
然后从开始向根节点路径压缩。假设从i到顶点一共有四层(也就是说,目前i城市里边有4颗龙珠,根节点龙珠是i号)
根结点为1号龙珠(根节点),然后第二层2号龙珠,第三层3号龙珠,第四层4号龙珠.那么,第一层路径压缩过程中进入第二层,然后第三层,然后第四层,第四层也就是根,找到根结点,返回第三层,第三层+上第四层的转移次数,然后返回第二层,第二层转移次数加上第三层转移次数,返回第一层,第一层转移次数加上第二层转移次数,同时,在这个过程中也把下面3层的结点的父节点直接更新为和根结点,也就是1相连。
下附代码:
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 10010;
int city[maxn];//表示i号城市有几个球
int parent[maxn];//表示i球在哪个城市
int transport[maxn];//表示i球被转移了几次
int t,n,q;
void makeset()
{
for(int i=0;i<=n;i++)
{
city[i] = 1;
parent[i] = i;
transport[i] = 0;
}
}
int findRoot(int x)
{
if(x == parent[x])
return x;
int tempRoot = parent[x];
parent[x] = findRoot(parent[x]);//路径压缩
transport[x] += transport[tempRoot];
return parent[x];
}
void Union(int x,int y)
{
int xRoot = findRoot(x);
int yRoot = findRoot(y);
if(xRoot != yRoot)
{
parent[xRoot] = yRoot;
transport[xRoot] = 1;
city[yRoot] += city[xRoot];
city[xRoot] = 0;
}
}
int main()
{
scanf("%d",&t);
int num = 1;
while(t--)
{
scanf("%d %d",&n,&q);
printf("Case %d:\n",num++);
makeset();
char str[10];
while(q--)
{
scanf("%s",str);
if(str[0] == 'T')
{
int x,y;
scanf("%d %d",&x,&y);
Union(x,y);
}
else if(str[0] == 'Q')
{
int x;
scanf("%d",&x);
int k =findRoot(x);
printf("%d %d %d\n",k,city[k],transport[x]);
}
}
}
return 0;
}