ybtoj【图论】1章3题&&SSL_1225&&P1196【银河英雄传说】

银河英雄传说

题目

银河英雄传说


解析

这道题目很明显是使用并查集,但这里要引入一种新的并查集:

边带权的并查集

这里的权,可以是很多东西,如距离等
那么这题为什么一定要用这一种呢?
假如不路径压缩,明显可以轻易求出,但是有一个大问题
超时
至于按秩合并,应该看一看以下文字:
含义为第i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。
合并有向,不能按秩合并
思路:
用三个数组分别存储这个节点的父亲,这个节点到父亲的距离,以及以这个节点为代表的连通块大小(不是代表则无效)

code:

#include<cstdio>
#include<cstring>
using namespace std;
char t;
int x,y,xx,yy,f[30010],c[30010],d[30010],q;
int abs(int dep){
    
    return (dep>-dep)?dep:-dep;}
bool isdigit(char t){
    
    return (t<='9'&&t>='0')?1:0;}
int find(int dep)
{
    
    
	if(f[dep]==dep)return dep;
	int l=find(f[dep]);
	c[dep]+=c[f[dep]];//累加路径影响
	return f[dep]=l;
}//查询(路径压缩)
inline int read()
{
    
    
	int num=0,f=1;
	char c=0;
	while(!isdigit(c=getchar())){
    
    if(c=='-')f=-1;}
	while(isdigit(c))num=(num<<1)+(num<<3)+(c&15),c=getchar();
	return num*f;
}//快读
int main()
{
    
    
	for(int i=1;i<=30000;i++)f[i]=i,d[i]=1;
	q=read();
	while(q--)
	{
    
    
		scanf(" %c ",&t);
		x=read(),y=read();
		if(t=='M')
		{
    
    
			xx=find(x),yy=find(y);
			c[xx]=d[yy];//让原以c为代表的节点获得正确的距离
			d[yy]+=d[xx];//大小增加
			f[xx]=yy;//改变父节点
		}
		else
		{
    
    
			if(find(x)!=find(y))printf("-1\n");
			else printf("%d\n",abs(c[x]-c[y])-1);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zhanglili1597895/article/details/112976891
今日推荐