题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3635

【问题描述】

有标号为1到n的n个龙珠,分别放在对应标号为1到n的n个城市里。 
下面有两种操作: 
T A B表示把A龙珠所在城市的所有龙珠都转移到B龙珠所在的城市中 
Q A 表示查询A,需要知道A龙珠现在所在的城市,A所在的城市有几颗龙珠,A转移到这个城市移动了多少次,分别输出3个整数,表示上述信息。

【输入描述】

第一行一个整数T表示测试数据组数T∈[0,100] 
对于每一组测试数据,第一行包含两个整数N,Q∈[2,10000] 
接下来Q行,每行包含如下的操作或询问:T A B或Q A,如题目描述所示。

【输出描述】

对于每一组测试数据,先输出一行Case x:(x表示测试数据标号,从1开始),然后对于每一个询问,输出一行三个数表示答案,用空格隔开

【样例输入】

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

开三个数组

pre数组:pre[i]表示第i个球所在的城市

sum数组:sum[i]表示第i个城市所拥有的球的个数

cnt数组:cnt[i]表示第i个球移动了几次

init():初始化,每一个球原来都呆在自己的城市,所以每一个城市里都只有1个球,每一个球的移动次数都是0。

如果输入的是T,x,y,则find函数找到x和y的根结点,在find函数递归的时候,先是一直延伸向下,找到它的根结点fx,然后在回溯的过程中修改cnt数组(即cnt[i]表示第i个球移动的次数)以及进行压缩路径。

某一个球移动的次数 = 他自己移动的次数 + 它上面的根结点移动的次数 ,所以find(pre[x])一直延伸向上找到最高的那一个点,然后再回溯的过程中加上每一个根结点移动的次数,逐个加上,涉及到的点都要进行路径压缩,把相应的点连接到fx上

举个例子:

一组测试数据:

3 4
T 1 2
Q 1
T 1 3
Q 1

第一步:

sum[1] = 1     cnt[1] = 0     pre[1]=1

sum[2] = 1     cnt[2] = 0     pre[2]=2

sum[3] = 1     cnt[3] = 0     pre[3]=3

第二步

在join函数中,find函数没有进行递归,直接返回,fx=1,fy=2,1连到2上,fx(就是x,也就是1)为根结点,移动次数被置为1,pre[1] = 2

第三步:

再次连接的时候,y=3,在调用find函数的时候,直接返回fy=3。但是,x=2,是先一直递归得到fx=2,回溯,退回到x=1,pre[1]=2,cnt[1] += cnt[2],这时候的cnt[2]=0,路径压缩,pre[1]=2,返回2给fx。之后pre[2] =3(得到的状态如上面那幅图所示,将1的根结点连接到3,用题目中的话来说就是将1所在的城市的所有龙珠转移到3城市中,所以3所在的城市的龙珠数量要加上1所在的城市的龙珠的数量,这是1和2在一个城市,之后因为都移走了,所以要置0),sum[3]+=sum[2],sum[2]=0。移动的那个根结点cnt的值置为1。

第四步:

在主函数中,假设要查找的结点是a,root来接受find(a)的值,在调用find函数的同时会进行路径压缩,图的状态会变成上面那种样子,先是x=3,直接返回3给fx,这是x=2了,cnt[2]+=cnt[3](cnt[3]=0,因为没有移动过),pre[2]=3,在返回3给fx,这时候x=1,cnt[1]+=cnt[2],所以cnt[1]变成了2,pre[1]=3,(fx一直接受的返回值都是3),所以,1也连接到3上去了。在最后的输出中,注意保存要查找的根结点就好,前两个输出的数都是要按照根结点来找的,最后一个是根据结点的序号去找的。

只要递归遍历到的点,都会直连到该集合的根节点下,如果遍历到的点还有子树,但是子树上的结点不涉及在这一次递归中,那么就直接一整棵子树连接到该集合的根节点上去。

在回退的过程中,一开始找到的fx(即那个集合的根结点)一直保存在fx中,就是为了pre[x]=fx。

例如要创建的是这样的一棵树,为了看出路径压缩的过程,我们在输入数据的时候,要从下网上输入。

Q 1

     

还是这一种状态,pre[1] = 1,之前都是其他的点的移动,最后是连接到1上,1没有移动过

Q 3

    

在递归的过程中,3,2,1,接着回溯,所以这三个点,最后都会路径压缩,直接连接到1上,像2和3还连接着其他子树,就直接一起,以2和3为根一起带过去了。

之后再Q 3 ,也不会发生改变了,因为已经路径压缩完成,是当前的最优状态了。

之后再试一下Q 4

     

(现在大家可以体会到递归以及路径压缩是怎么一回事了吗)

#include <iostream>
#include <cstring>
#include <cstdio>using namespace std;const int maxn = 10005;int pre[maxn];
int sum[maxn];
int cnt[maxn];
int n,m,root;
char str[3];void init()
{for(int i=0;i<maxn;i++){pre[i] = i;sum[i] = 1;cnt[i] = 0;}
}int find(int x)
{if(x==pre[x])return x;int fx = find(pre[x]);cnt[x] += cnt[pre[x]];pre[x] = fx;return fx;
}void join(int x,int y)
{int fx = find(x);int fy = find(y);if(fy==fx)return ;pre[fx] = fy;sum[fy] += sum[fx];sum[fx] = 0;cnt[fx] = 1;
}int main ()
{int T,k=1,i;int x,y,a;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);printf("Case %d:\n",k++);init();while(m--){scanf("%s",str);if(str[0]=='T'){scanf("%d%d",&x,&y);join(x,y);}else if(str[0]=='Q'){scanf("%d",&a);root = find(a);/*for(i=1;i<=n;i++){printf("pre[%d]=%d\n",i,pre[i]); }*/printf("%d %d %d\n",root,sum[root],cnt[a]);}/*for(i=1;i<=n;i++){cout << "sum["<<i<<"] = " << sum[i] << ",pre["<<i << "] = "<<pre[i] << ",cnt["<<i<<"] = " << cnt[i]<< endl;}*/}}return 0;
}

【HDU】3635 Dragon Balls (带权并查集 一)相关推荐

  1. hdu 3635 Dragon Balls(加权并查集)2010 ACM-ICPC Multi-University Training Contest(19)

    这道题说,在很久很久以前,有一个故事.故事的名字叫龙珠.后来,龙珠不知道出了什么问题,从7个变成了n个. 在悟空所在的国家里有n个城市,每个城市有1个龙珠,第i个城市有第i个龙珠. 然后,每经过一段时 ...

  2. hdu3635 Dragon Balls(带权并查集)

    /* 题意:有N个城市, 每一个城市都有一个龙珠(编号与城市的编号相同),有两个操作 T A ,B 将标号为A龙珠所在城市的所有的龙珠移动到B龙珠所在城市中!  思路:并查集 (压缩路径的时候将龙珠移 ...

  3. HDU 3047 Zjnu Stadium (带权并查集)

    链接: http://acm.hdu.edu.cn/showproblem.php?pid=3047 题目: Problem Description In 12th Zhejiang College ...

  4. How Many Answers Are Wrong HDU - 3038(带权并查集经典题,满满的都是注释)

    How Many Answers Are Wrong HDU - 3038  点击打开链接 题意:现在有n个数(你并不知道这n个数是什么),m次查询,每次查询给出u,v,w.表示从第u个数到第v个数的 ...

  5. Valentine's Day Round hdu 5176 The Experience of Love [好题 带权并查集 unsigned long long]

    传送门 The Experience of Love Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Ja ...

  6. How Many Answers Are Wrong HDU - 3038(带权并查集)

    TT and FF are - friends. Uh- very very good friends -________-b FF is a bad boy, he is always wooing ...

  7. HDU 5176 The Experience of Love 带权并查集

    The Experience of Love Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/O ...

  8. 带权并查集 HDU - 3047

    题意: 一圈座位有n个,给出m组序号之间的关系,比如,1 2 150 代表2号坐在1号位置序号+150,看m组数据有多少组冲突的. 思路: 带权并查集模板. #include<stdio.h&g ...

  9. 【POJ - 1703】Find them, Catch them(带权并查集之--种类并查集 权为与父节点关系)

    题干: Find them, Catch them Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 36176   Accep ...

  10. HDU-3234 Exclusive-OR 异或带权并查集

    题目描述 现在有n个数,X0,X1,-,Xn-1,你并不知道这n个数的大小,然后接下来有Q个询问,询问的格式如下 1) I p v, 告诉你 Xp = v 2) I p q v, 告诉你 Xp ^ X ...

最新文章

  1. 西农韦革宏组揭示甘草根系微生物群落分布及其与根内次级代谢产物之间的联系...
  2. 操作系统-银行家算法
  3. salt 执行命令等待_saltstack异步执行命令
  4. mysql 存储过程调用权限消失的问题,恢复权限
  5. OSChina 周一乱弹 ——程序员用代码写的爱情
  6. python时间处理模块有哪些_Python模块之时间处理
  7. @excel注解_Excel导入导出Java解决方案推荐
  8. 收藏 | 卷积神经网络中10大拍案叫绝的操作!
  9. 2011年12月1日学习内容总结
  10. OpenCV 图像金字塔buildPyramid、pyrDown、pyrUp
  11. validate中remote的用法
  12. 【Win 10 应用开发】手写识别
  13. 王建林的一个亿,靠打工能实现么?
  14. vb.net中如何结束一个线程
  15. android 文件md5校验失败怎么办,更新包md5校验失败的4个原因和解决方法!游戏lol更新md5验证失败...
  16. JAVA实现网页版斗地主_java实现斗地主小案例
  17. JS变量特点及分号用法
  18. Google Adsense西联快汇收款流程
  19. 在html中什么是锚点
  20. 惯性导航工作原理及系统分类

热门文章

  1. 如何打造一流的视觉AI技术
  2. VBA中级班课时3小结
  3. 如何用 Graylog 管理日志?- 每天5分钟玩转 Docker 容器技术(93)
  4. ES5和ES6数组遍历方法详解
  5. shell 脚本逐行读取多个文件,并逐行对应
  6. SQL Server 2005/2008 用户数据库文件默认路径和默认备份路径修改方法
  7. poj 2063完全背包
  8. 美通信与动力公司向WIN-T军事通信计划提供支持
  9. 如何将本地项目上传到自己的GitHub上
  10. Android提前加载unity程序,Unity项目嵌入Android App实现过程