【並查集】銀河英雄傳說
題目描述
公元5801年,地球居民遷移至金牛座α第二行星,在那裡發表銀河聯邦創立宣言,同年改元為宇宙曆元年,並開始向銀河系深處拓展。
宇宙歷799年,銀河系的兩大軍事集團在巴米利恩星域爆發戰爭。泰山壓頂集團派宇宙艦隊司令萊因哈特率領十萬餘艘戰艦出征,氣吞山河集團點名將楊威利組織麾下三萬艘戰艦迎敵。楊威利擅長排兵佈陣,巧妙運用各種戰術屢次以少勝多,難免恣生驕氣。
在這次決戰中,他將巴米利恩星域戰場劃分成30000列,每列依次編號為1, 2, …, 30000。之後,他把自己的戰艦也依次編號為1, 2, …, 30000,讓第i號戰艦處於第i列(i = 1, 2, …, 30000),形成“一字長蛇陣”,誘敵深入。這是初始陣形。
當進犯之敵到達時,楊威利會多次釋出合併指令,將大部分戰艦集中在某幾列上,實施密集攻擊。合併指令為M i j,含義為讓第i號戰艦所在的整個戰艦佇列,作為一個整體(頭在前尾在後)接至第j號戰艦所在的戰艦佇列的尾部。顯然戰艦佇列是由處於同一列的一個或多個戰艦組成的。合併指令的執行結果會使佇列增大。
然而,老謀深算的萊因哈特早已在戰略上取得了主動。在交戰中,他可以通過龐大的情報網路隨時監聽楊威利的艦隊調動指令。 在楊威利釋出指令調動艦隊的同時,萊因哈特為了及時瞭解當前楊威利的戰艦分佈情況,也會發出一些詢問指令:C i j。該指令意思是,詢問電腦,楊威利的第i號戰艦與第j號戰艦當前是否在同一列中,如果在同一列中,那麼它們之間佈置有多少戰艦。
作為一個資深的高階程式設計員,你被要求編寫程式分析楊威利的指令,以及回答萊因哈特的詢問。 最終的決戰已經展開,銀河的歷史又翻過了一頁……
輸入
第一行有一個整數T(1≤T≤500,000),表示總共有T條指令。
以下有T行,每行有一條指令。指令有兩種格式:
1. M i j :i和j是兩個整數(1≤i , j≤30000),表示指令涉及的戰艦編號。該指令是萊因哈特竊聽到的楊威利釋出的艦隊調動指令,並且保證第i號戰艦與第j號戰艦不在同一列。
2. C i j :i和j是兩個整數(1i , j30000),表示指令涉及的戰艦編號。該指令是萊因哈特釋出的詢問指令。
輸出
你的程式應當依次對輸入的每一條指令進行分析和處理:
如果是楊威利釋出的艦隊調動指令,則表示艦隊排列發生了變化,你的程式要注意到這一點,但是不要輸出任何資訊;
如果是萊因哈特釋出的詢問指令,你的程式要輸出一行,僅包含一個整數,表示在同一列上,第i號戰艦與第j號戰艦之間佈置的戰艦數目。如果第i號戰艦與第j號戰艦當前不在同一列上,則輸出-1。
樣例輸入
(如果複製到控制檯無換行,可以先貼上到文字編輯器,再複製)
4
M 2 3
C 1 2
M 2 4
C 4 2
樣例輸出
-1
1
提示
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------【分析】 非常經典的帶權並查集問題。 為表示方便,設f[]為該元素的父親,v[]為該元素到父親的距離,l[]為該列長度。 我們可以把每一艘戰艦看做一個元素。當合並a和b時,將a和b的祖先x和y搞出來 ,再將f[x]置為y,v[x]置為l[x]就行了。 查詢的時候,我們就可以將v[a]和v[b]算出來,然後輸出|v[a]-v[b]|-1。 注意:v[a]-v[b]可能為0,所以要進行特判。 【WA了很多遍的程式碼】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#include<cstdio>
int
set[30005], v[30005], l[30005];
int
ab(
int
n)
{
return
n < 0 ? -n : n;
}
int
f(
int
x)
{
if
(set[x] == x)
return
x;
v[x] += v[set[x]], l[x] = l[set[x]];
return
set[x] = f(set[x]);
}
int
main()
|