并查集初级题目
题目链接:点击打开链接
题意:
1、每个城市初始有一个龙珠,father[i] = i初始化数组,
2、每个城市的龙珠可以移动,T A B 包含A龙珠的城市的所有龙珠都转移到包含B龙珠的城市中去
3、Q X,输出X龙珠所在城市、所在城市拥有的龙珠数量、X龙珠被移动过的次数
思路:
简单并查集,但是考虑到路径压缩会造成X龙珠移动次数计算错误(详见百度并查集路径压缩原理),所以不进行路径压缩,
直接使用一个数组c[MAXN]来记录每个地点(而不是龙珠)被移动过的次数,最后通过遍历(搜索你的根节点),每次加上经过地点的权重。
#include<stdio.h>
#include<iostream>
using namespace std;
int father[10005];
int c[10005];
int size[10005];
void init(int n)//初始化
{
for(int i = 1 ; i <= n ; i ++)
{
father[i] = i;
c[i] = 0;
size[i] = 1;
}
}
int find(int x)//由于路径压缩有后遗症
{//因此不进行路径压缩
int i = x;
while(father[i] != i)
{
i = father[i];
}
return i;
}
int f(int x)
{//使用函数求一个每个球走过的地方
//对于每个球来说,遍历数组,他走过的路径为每个地点的c[i]值
int i = x;
int ans = 0;
while(father[i] != i)
{
ans += c[i];
i = father[i];
}
return ans;
}
void merge(int x,int y)
{//合并操作,同时计算每个地点有几个球
int fx = find(x);
int fy = find(y);
size[fy] += size[fx];
size[fx] = 0;
if(fx!=fy)
{
father[fx] = fy;
}
}
int main()
{
int n,m;
int x,y;
int T;
scanf("%d",&T);
int kk = T;
while(T--)
{
scanf("%d %d",&n,&m);
printf("Case %d:\n",kk-T);
init(n);
for(int i = 1 ; i <= m; i ++)
{
char t;
int a;
getchar();
scanf("%c",&t);
if(t == 'T')
{
scanf("%d %d",&x,&y);
c[find(x)]++;//对应每一个地点使用次数加一
merge(x,y);
}
else if(t == 'Q')
{
scanf("%d",&a);
printf("%d %d %d\n",find(a),size[find(a)],f(a));
}
}
}
return 0;
}