P1196 [NOI2002] 銀河英雄傳說

土木牢盖發表於2024-11-27

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;
}



相關文章