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 行,每行有一條指令。指令有兩種格式:
M i j
:i 和 j 是兩個整數(1≤i,j≤30000),表示指令涉及的戰艦編號。該指令是萊因哈特竊聽到的楊威利釋出的艦隊調動指令,並且保證第 i 號戰艦與第 j 號戰艦不在同一列。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;
}