http://acm.hdu.edu.cn/showproblem.php?pid=3635
题目大意:
初始时,有n个龙珠,编号从1到n,分别对应的放在编号从1到n的城市中。
现在又2种操作:
T A B,表示把A球所在城市全部的龙珠全部转移到B城市。(第一次时,因为A球所在的城市只有一个球,所以只移动1个,如果有多个,则全部移动)。
Q A,表示查询A。要求得到的信息分别是:A现在所在的城市,A所在城市的龙珠数目,A转移到该城市移动的次数(如果没有移动就输出0)
通过路径压缩来更新转移的次数,比如每次移动时,我只需要把这个城市的根结点的转移次数+1,等到以后路径压缩时,子结点自己移动的次数加上根结点移动的次数,就是这个结点总共的移动次数,不明白的可以自己动手画画。。
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 10015;
const int inf = 1<<30;
int n,q;
int p[maxn],counts[maxn],tran[maxn];
int find( int x )
{
if( p[x] == x )
return x;
else{
int temp = p[x];
p[x] = find(p[x]);
tran[x] += tran[temp];
return p[x];
}
}
void merge( int u,int v )
{
int x = find(u);
int y = find(v);
if( x != y ){
p[x] = y;
tran[x] ++;
counts[y] += counts[x];
counts[x] = 0;
}
}
void init()
{
for( int i = 1; i <= n; i ++ ){
p[i] = i;
counts[i] = 1;
tran[i] = 0;
}
}
int main()
{
//freopen("data.txt","r",stdin);
int cas,u,v;
char ch;
scanf("%d",&cas);
for( int c = 1; c <= cas; c ++ ){
scanf("%d%d",&n,&q);
init();
printf("Case %d:\n",c);
for( int i = 1; i <= q; i ++ ){
scanf("%*c%c", &ch);
if( ch == 'T' ){
scanf("%d%d",&u,&v);
merge(u,v);
}
else{
scanf("%d",&u);
v = find(u);
printf("%d %d %d\n",v,counts[v],tran[u]);
}
}
}
return 0;
}
int find(int x)
{
int k, j, r;
r = x;
while(r != parent[r]) //查找跟节点
r = parent[r]; //找到跟节点,用r记录下
k = x;
while(k != r) //非递归路径压缩操作
{
j = parent[k]; //用j暂存parent[k]的父节点
parent[k] = r; //parent[x]指向跟节点
k = j; //k移到父节点
}
return r; //返回根节点的值
}