【Ybtoj第10章例3】銀河英雄伝説【コンバインコレクション】

ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入
ここに画像の説明を挿入


問題解決のアイデア

この質問では、ユニオン検索セットの拡張使用法を紹介します。サイドバンド加重ユニオン検索セットです。

ここでのエッジの重みは、特定のノードとその親ノードの間の距離、または値の合計と排他的ORの合計などの多くの情報を表すことができます。一般的なアプローチは通常のユニオン検索のアプローチと似ていますが、セットとパス圧縮をマージするときにエッジの重みを更新する必要があります。

この質問に戻ると、ユニオンを使用して、メンテナンス戦艦が同じ列にあるかどうかを確認できます。各列の最初の戦艦がコレクションの代表として使用されます。disdisを使用します。D私は、エッジの右、記録DISX dis_xをd i sX番号が付けられた戦艦xから番号が付けられたファックスfa_xを表しますf aX戦艦の中にはいくつかの戦艦(xを含まない)があり、同時にnumnumを維持しますn u m配列、numx num_xn u mXxを代表要素として、コレクションに含まれる軍艦の数を示します。
クエリ操作では、最初にx、yx、yを判断しますxyが同じ列にあるかどうか(およびセットの代表的な要素が同じであるかどうか)、それらと代表的な要素の間に軍艦がいくつあるかを調べ、減算によって得られた差が答えです。


コード

#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<bitset>
using namespace std;

int  T,x,y,fa[30010],num[30010],dis[30010];
char c;

int find(int x)
{
    
    
	if(fa[x]==x)return fa[x];	
	int v=find(fa[x]);
	dis[x]=dis[fa[x]]+dis[x];//自己到新爸爸的距离,等于自己的原爸爸到新爸爸的距离,加上自己到原爸爸的距离
	return fa[x]=v;
}

int main(){
    
    
	scanf("%d",&T);
	for(int i=1;i<=30009;i++)
		fa[i]=i,num[i]=1;
	while(T--)
	{
    
    
		cin>>c;
		scanf("%d%d",&x,&y);
		int xx=find(x),yy=find(y);
		if(c=='M')
		{
    
    
			fa[xx]=yy;
			dis[xx]=num[yy];//加上到新爸爸的距离(新增距离相当于新爸爸所在集合的长度)
			num[yy]+=num[xx];//加上新合并进来的长度
			num[xx]=0;//不存在了,被合并了
		}
		if(c=='C')
		{
    
    
			if(xx!=yy) printf("-1\n");
			else printf("%d\n",abs(dis[y]-dis[x])-1);//两飞船间距离
		}
	}
}

おすすめ

転載: blog.csdn.net/kejin2019/article/details/115212348