NYOJ431
样例输入
2
3 3
T 1 2
T 3 2
Q 2
3 4
T 1 2
Q 1
T 1 3
Q 1
样例输出
Case 1:
2 3 0
Case 2:
2 2 1
3 3 2
题意:起初球i是被放在i号城市的,在年代更迭,世事变迁的情况下,球被转移了,而且转移的时候,连带该城市的所有球都被移动了:T A B(A球所在的城市的所有球都被移动到了B球所在的城市),Q A(问:A球在那城市?A球所在城市有多少个球呢?A球被转移了多少次呢?)。
本题主要是用到并查集。 难点为, 怎么保存转移次数。 考虑并查集的路径压缩,就是通过路径压缩来更新转移的次数,比如每次移动时,我只需要把这个城市的根结点的转移次数+1,等到以后路径压缩时,子结点自己移动的次数加上根结点移动的次数,就是这个结点总共的移动次数。我们可以用一个tran表示此节点距离它自己现在的祖先(f数组)的转移次数,有点难理解,也就是说如图所示#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
const int maxn=100100;
int f[maxn],tran[maxn],sum[maxn];
int af,bf,a,b,T,n,m;
char s[2];
void close()
{
fclose(stdin);
fclose(stdout);
exit(0);
}
int getfather(int k)
{
if (k==f[k])
return k;
return getfather(f[k]);
}
int find(int k)
{
if (f[k]==k)
return k;
int t=f[k];
f[k]=find(f[k]);
if (t!=f[t])
tran[k]+=tran[t];
return f[k];
}
void work()
{
}
void init ()
{
freopen("dragon.in","r",stdin);
freopen("dragon.out","w",stdout);
scanf("%d",&T);
int cnt=0;
while (T--)
{
cnt++;
printf("Case %d:\n",cnt);
memset(tran,0,sizeof(tran));
memset(f,0,sizeof(f));
scanf("%d %d",&n,&m);
for (int i=1;i<=n;i++)
{
f[i]=i;
sum[i]=1;
}
for (int i=1;i<=m;i++)
{
scanf("%s",s);
if (s[0]=='T')
{
scanf("%d %d",&a,&b);
af=getfather(a);
bf=getfather(b);
f[af]=bf;
tran[af]++;
sum[bf]+=sum[af];
}
else
{
scanf("%d",&a);
af=find(a);
printf("%d %d %d\n",af,sum[af],tran[a]);
}
}
}
}
int main ()
{
init();
work();
close();
return 0;
}
#include<stdio.h>
int t,a,b,n,q,cnt[10005];
char s[5];
struct C
{
int pre,num;
}fa[10005];
void In()
{
scanf("%d %d%*c",&n,&q);
for(int i=1;i<=n;i++) {
fa[i].pre=i;
fa[i].num=1;
cnt[i]=0; //每个点移动次数一开始都是0
}
}
int Find(int x)
{
if(x!=fa[x].pre) {
int tmp=fa[x].pre;
fa[x].pre=Find(fa[x].pre);
cnt[x]+=cnt[tmp]; // 加上它父亲的移动次数。
}
return fa[x].pre;
}
int main()
{
scanf("%d%*c",&t);
for(int ca=1;ca<=t;ca++) {
In();
printf("Case %d:\n",ca);
for(int k=1;k<=q;k++) {
scanf("%s ",s);
if(s[0]=='T') {
int fx,fy;
scanf("%d %d%*c",&a,&b);
fx=Find(a);
fy=Find(b);
if(fx!=fy) {
fa[fy].num+=fa[fx].num;
fa[fx].num=0;
fa[fx].pre=fy;
cnt[fx]=1; // 祖先节点只会移动一次。
}
} else {
scanf("%d%*c",&a);
int fx=Find(a);
printf("%d %d %d\n",fx,fa[fx].num,cnt[a]);
}
}
}
return 0;
}