P1196 [NOI2002]银河英雄传说

题目

P1196 [NOI2002]银河英雄传说

分析

对于M指令,一次移动整列,并且是把两列合并成一列。

对于C指令:判断飞船 i 和飞船 j 是否在同一列,若在,则输出它们中间隔了多少艘飞船。

由于需要判断是否在同一列,每列初始都只有一艘飞船,之后需要不断合并,所以很容易就想到要用并查集来实现。

AC代码
#include <iostream>
#include <cmath>
using namespace std;
int f[30001], dis[30001], num[30001];
/*
f[i]:i的祖先,即飞船前一个飞船 
dis[i]:飞船与它所在列头的距离,初始为 0 
num[i]:第 i 列飞船的数量,初始为 1 
*/ 
//  初始化						
void init()
{
	for (int i = 1; i <= 30000; ++i) 
	{                               
		f[i] = i;
		dis[i] = 0;
		num[i] = 1;
	}
} 

int find(int x) 
{                                       
	if (f[x] == x)
	{
		return f[x];
	}
	
	int fn = find(f[x]);//  以后尽量这样写,对付带权并查集                                  
	dis[x] += dis[f[x]];//  回溯时更新 
									
	return f[x] = fn;
}

int main() 
{
	init();
	int t;
	cin >> t;
	while (t--) 
	{
		char c;
		int x, y;
		cin >> c >> x >> y;
		int h1 = find(x);                                   
		int h2 = find(y);                                   
		if (c == 'M') {
			f[h1] = h2; //  h1放在h2后面 
			dis[h1] += num[h2];//  那么h2尾部距离列头更远                                     
			num[h2] += num[h1];//  那么h2列增加飞船数量增加     
			num[h1] = 0;//   h1列没有飞船了   
		}
		else 
		{
			if (h1 != h2)
			{
				cout << -1 << endl;      
			}  
			else 
			{
				cout << abs(dis[x] - dis[y]) - 1 << endl;  
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值