题目
题解
关于这一道题目,想到使用并查集,真的是大神!!!
在这道题目中,通过阅读英文题目,发现它有并查集的影子!
在移动的时候,它是把A所在的一摞(所有的)挪动到B所在的一摞(所有的)的最上面
这就需要快速地判断哪些是在一摞上.
所以猜想使用并查集;
再想:应该把最底下的哪一个叫做根,因为比较稳定
事实上:并查集并不是仅仅用来判断是不是在一个集合里边,还可以有拓展的用途.
(比如记录某一个点到根节点的距离(在这里,我尚且把箱子的个数抽象为距离))
这个距离可以使用一次一次找爸爸的过程来进行求解, 同时还可以路径压缩
代码
#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
using namespace std;
#define MAX 30009
int fa[MAX];
int dis[MAX];
int num[MAX];
int find(int x)//注意找的时候要顺便进行路径压缩,在这个过程中,dis的值也要进行更改
//由于这样,所以就不许要在单独设计一个找下面有多少个箱子的函数,直接先来一个find,直接输出dis[i]
{
if (x != fa[x])//自己不是根节点
//整个return递归采用了回溯的方法
{
int ret = find(fa[x]);
dis[x] += dis[fa[x]];
fa[x] = ret;
return ret;
}
else
{
return x;
}
}
void move(int x, int y)
{
int fx = find(x);
int fy = find(y);
fa[fx] = fy;
dis[fx] += num[fy];
num[fy] += num[fx];
}
int main()
{
int T;
scanf("%d", &T);
for (int i = 1; i <= 30000; i++)
{
num[i] = 1;
fa[i] = i;
}
while (T--)
{
char buf[12];
int t1, t2;
scanf("%s", buf);
if (*buf == 'M')//移动
{
scanf("%d%d", &t1, &t2);
move(t1, t2);
}
else//查询
{
scanf("%d", &t1);
find(t1);
printf("%d\n", dis[t1]);
}
}
return 0;
}