洛谷P1196银河英雄传说(带权并查集)

题目传送,嘿嘿

分析:带权并查集,利用一个数组来存储每个飞船的位置,值得注意的是,当用并查集进行压缩时,需要记录队列的长度,否则你得到的只是你本身位置加上根节点的位置的长度(这里容易翻车),还有就是压缩时,位置的更新也需要注意。也是很容易出BUG的。

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn = 50010;
int fa[maxn], num[maxn];
int T;
int loc[maxn];

/*int find(int x)
{
    //错误代码路径压缩时,位置更新不明确。
	int r = x;
	while (r != fa[r])
	{
		loc[r] += loc[fa[r]];
		r = fa[r];
		
	}
	int i = x, j;
	while (fa[i] != r)
	{
		loc[i] += loc[r];
		j = fa[i];
		fa[i] = r;
		i = j;
	}
	
	return r;
}*/
int find(int x) {                                        //查找祖先的函数 
	if (fa[x] == x)return fa[x];
	int fn = find(fa[x]);                                    //先递归找到祖先 
	loc[x] += loc[fa[x]];    //在回溯的时候更新fa(因为更新时要用到正确的fa[祖先],
						 //所以只能在回溯的时候更新) 
	return fa[x] = fn;
}

void unite(int x, int y)
{
	int fx = find(x);
	int fy = find(y);
	if (fx != fy)
	{
		loc[fx] += num[fy];
		fa[fx] = fy;
		num[fy] += num[fx];//用num记录队列长度防止出现下面1情况。
		num[fx] = num[fy];
		//loc[fx] += loc[fy]+1;//合并时这样判断长度出错,这样直接加在了
		//头元素后面而忽略了原有的队列长度。
		find(x); find(y);
	}
}
int main()
{
	scanf("%d", &T);

	for (int i = 0; i <= 30000; i++)
	{
		fa[i] = i;
		num[i] = 1;
		loc[i] = 0;
	}
	//memset(loc, 0, sizeof(loc));
	for (int i = 0; i < T; i++)
	{
		int a, b;
		char c;
		cin >> c;
		scanf("%d%d", &a, &b);
		int fx = find(a), fy = find(b);
		if (c == 'M')
		{
			unite(a, b);
			
		}
		else if (c == 'C') {
			
			if (fx != fy)
			{
				printf("-1\n");
			}
			else {
				int d;
				d = abs(loc[a] - loc[b]);
				/*if (loc[b] > loc[a])
					d = loc[b] - loc[a];
				else
				{
					d = loc[a] - loc[b];
				}*/
				printf("%d\n", d - 1);
			}
		}
	}

	return 0;
}

猜你喜欢

转载自blog.csdn.net/fighting_yifeng/article/details/81394126