P1196 [NOI2002] 银河英雄传说

P1196 [NOI2002] 银河英雄传说

A将战舰划分成30000列,每列依次编号为1,2,...,30000。战舰也依次编号为 1,2,...,30000,让第i 号战舰处于第i 列。

合并指令为M i j,第i号战舰整体(头在前尾在后)接至第 j号战舰所在队列的尾部。战舰队列是由处于同一列的战舰组成的。

B在A发布指令调动舰队的同时,也会发出一些询问指令:C i j。A的第i号战舰与第j号战舰当前是否在同一列中,如果在同一列中,那么它们之间布置有多少战舰。

输入格式

第一行有一个整数 T(1≤T≤5×105),表示总共有 T 条指令。

以下有 T 行,每行有一条指令。指令有两种格式:

  1. M i j:i 和 j 是两个整数(1≤i,j≤30000),表示指令涉及的战舰编号。该指令是莱因哈特窃听到的杨威利发布的舰队调动指令,并且保证第 i 号战舰与第 j 号战舰不在同一列。
  2. C i j:i 和 j 是两个整数(1≤i,j≤30000),表示指令涉及的战舰编号。该指令是莱因哈特发布的询问指令。

输出格式

  • 调动指令不要输出任何信息。
  • 询问指令:在同一列上,输出第 i 号战舰与第 j 号战舰之间布置的战舰数目。不在同一列上,则输出 −1。

**输入 **

4
M 2 3
C 1 2
M 2 4
C 4 2

**输出 **

-1
1

样例解释

战舰位置图:表格中阿拉伯数字表示战舰编号

题目中没有强制 \(i \neq j\),但是实测数据中不存在 \(i = j\) 的情况

#include <bits/stdc++.h>
using namespace std;
const int N = 3e4 + 10;
int f[N] , d[N] , fumo[N] , a , b , t , m , n;
char c;
// 查找函数
int find(int x) {
    if (f[x] == x) return x;
    int m = f[x];//记录x的父节点
    int n = find(f[x]);//递归查找父节点的根节点
    f[x] = n;//路径压缩
    d[x] += d[m];//// 更新x到根节点的距离
    return n;
}

// 合并函数
void baka(int m, int n) {
    m = find(m);//仙找根节点
    n = find(n);
    if (m!= n) {
        f[m] = n;
        d[m] = fumo[n];
        fumo[n] += fumo[m];
    }
}

int main() {
    scanf("%d", &t);
    // 初始化
    for (int i = 1; i <= 30000; i++) {
        f[i] = i;//父节点初始化为自己
        fumo[i] = 1;//开始每个元素单独构成一个集合
        d[i] = 0;//每个元素是自己的根节点
    }
    while (t--) 
	{
        scanf(" %c %d %d", &c, &a, &b);
        if (c == 'M')baka(a, b);
        else {
            m = find(a);n = find(b);
            if (m!= n) 
			{
                printf("-1\n");
            } else {
                printf("%d\n", abs(d[a] - d[b]) - 1);//初始d[i]为0,计算中间个数的时候要减1
            }
        }
    }
    return 0;
}



posted @ 2024-11-27 02:02  土木牢盖  阅读(23)  评论(0)    收藏  举报