公元五八○一年,地球居民遷移至金牛座α第二行星,;宇宙歷七九九年,銀河系的兩大軍事集團在巴米利恩星;楊威利擅長排兵佈陣,巧妙運用各類戰術多次以少勝多;然而,老謀深算的萊因哈特早已在戰略上取得了主動;在楊威利發佈指令調動艦隊的同時,萊因哈特爲了及時;做爲一個資深的高級程序設計員,你被要求編寫程序分;輸入文件;第一行有一個整數t(1?t?500,000),表;m函數
公元五八○一年,地球居民遷移至金牛座α第二行星,在那裏發表銀河聯邦創立宣言,同年改元爲宇宙曆元年,並開始向銀河系深處拓展。spa
宇宙歷七九九年,銀河系的兩大軍事集團在巴米利恩星域爆發戰爭。泰山壓頂集團派宇宙艦隊司令萊因哈特率領十萬餘艘戰艦出征,氣吞山河集團點名將楊威利組織麾下三萬艘戰艦迎敵。設計
楊威利擅長排兵佈陣,巧妙運用各類戰術多次以少勝多,不免恣生驕氣。在此次決戰中,他將巴米利恩星域戰場劃分紅30000列,每列依次編號爲1,2,…,30,000。以後,他把本身的戰艦也依次編號爲1, 2, …, 30000,讓第i號戰艦處於第i列(i=1, 2, …,30,000),造成「一字長蛇陣」,誘敵深刻。這是初始陣形。當進犯之敵到達時,楊威利會屢次發佈合併指令,將大部分戰艦集中在某幾列上,實施密集攻擊。合併指令爲mij,含義爲讓第i號戰艦所在的整個戰艦隊列,做爲一個總體(頭在前尾在後)接至第j號戰艦所在的戰艦隊列的尾部。顯然戰艦隊列是由處於同一列的一個或多個戰艦組成的。合併指令的執行結果會使隊列增大。隊列
然而,老謀深算的萊因哈特早已在戰略上取得了主動。在交戰中,他能夠經過龐大的情報網絡隨時監聽楊威利的艦隊調動指令。ip
在楊威利發佈指令調動艦隊的同時,萊因哈特爲了及時瞭解當前楊威利的戰艦分佈狀況,也會發出一些詢問指令:cij。該指令意思是,詢問電腦,楊威利的第i號戰艦與第j號戰艦當前是否在同一列中,若是在同一列中,那麼它們之間佈置有多少戰艦。ci
做爲一個資深的高級程序設計員,你被要求編寫程序分析楊威利的指令,以及回答萊因哈特的詢問。 最終的決戰已經展開,銀河的歷史又翻過了一頁……input
輸入文件cmd
第一行有一個整數t(1?t?500,000),表示總共有T條指令。 如下有T行,每行有一條指令。指令有兩種格式:it
mij:i和j是兩個整數(1?i,j?30,000),表示指令涉及的戰艦編號。該指令是萊因哈特竊聽到的楊威利發佈的艦隊調動指令,而且保證第i號戰艦與第j號戰艦不在同一列。
cij:i和j是兩個整數(1?i,j?30,000),表示指令涉及的戰艦編號。該指令是萊因哈特發佈的詢問指令。
輸出文件
你的程序應當依次對輸入的每一條指令進行分析和處理:
若是是楊威利發佈的艦隊調動指令,則表示艦隊排列發生了變化,你的程序要注意到這一點,可是不要輸出任何信息;
若是是萊因哈特發佈的詢問指令,你的程序要輸出一行,僅包含一個整數,表示在同一列上,第i號戰艦與第j號戰艦之間佈置的戰艦數目。若是第i號戰艦與第j號戰艦當前不在同一列上,則輸出-1。
輸入輸出樣例
galaxy.in 4
M 2 3 C 1 2 M 2 4 C 4 2
galaxy.out -1 1
樣例說明
戰艦位置圖:表格中阿拉伯數字表示戰艦編號
同一列的戰艦組成一個並查集,集合中的一個結點對應一艘戰艦。並以當前列的第一艘戰艦做爲集合的表明,並查集的數據類型採用樹型,樹的根結點即爲集合的表明。
試題不只要求判別兩個結點是否在同一個集合(即兩艘戰艦是否在同一列),並且還要求計算結點在有序集合的位置(即每一艘戰艦相隔同列的第一艘戰艦幾個位置,簡稱相對位置)。
const
maxn=30000; var
x,y:integer;
i,cmdcount:longint; ch:char;
father,count,behind:array[1..maxn] of integer; fin,fout:text;
1. 查找根結點,並進行路徑壓縮
function find_father(x:integer):integer; {查找結點X所在樹的根結點,並對該樹進行路徑壓縮} var
i,j,f,next:integer; begin
i:=x; while father[i]<>i do i:=father[i]; f:=i; {找出結點X所在樹的根結點?f}
i:=x; {按照自上而下的順序處理X的祖先結點} while i<>f do begin
next:=father[i];
father[i]:=f; {把結點i的父結點調整爲f,完成路徑壓縮} j:=next; repeat
behind[i]:=behind[i]+behind[j]; {calculate behind迭代,迭代求出路徑上每個子結點相對於f的相對位置} j:=father[j]; until father[j]=j; i:=next; end;
find_father:=f; {函數返回結點X所在樹的根結點} end;
2. 計算合併指令
procedure moveship(x,y:integer); {把X所在的集合併入Y所在的集合} var
fx,fy:integer; begin
fx:=find_father(x);
fy:=find_father(y); {分別計算X,Y所在的子樹父結點的序號}
father[father[fx]]:=fy; {若X,Y不在同一棵樹內,合併子樹。X所在子樹的根結點調整爲Y的子樹的根結點}
behind[fx]:=behind[fx]+count[fy]; {{根據調整後的X和Y關係,計算X的相對根結點位置要增長count[fy]} count[fy]:=count[fy]+count[fx]; {X併入Y所在的子樹,計算新集合的結點數} end;
試題不只要求判別兩個結點是否在同一個集合(即兩艘戰艦是否在同一列),並且還要求計算結點在有序集合的位置(即每一艘戰艦相隔同列的第一艘戰艦幾個位置,簡稱相對位置)。 procedure checkship(x,y:integer); var
f1,f2:integer; begin
f1:=find_father(x);
f2:=find_father(y); {分別計算X,Y所在的子樹父結點的序號}
if f1<>f2 then writeln(fout,-1) {若X,Y不在一棵樹中,則返回-1}
else writeln(fout,abs(behind[x]-behind[y])-1); {不然返回X和Y間隔的戰艦數} end;
begin
assign(fin,'galaxy1.in');reset(fin);
assign(fout,'galaxy1.out');rewrite(fout);
for i:=1 to maxn do{初始時爲每一艘戰艦創建一個並查集} begin
father[i]:=i; count[i]:=1; behind[i]:=0; end;
readln(fin,cmdcount); {讀指令數}
for i:=1 to cmdcount do{順序處理每一條指令} begin
read(fin,ch); {讀第i條指令的類型} case ch of
'M' : begin readln(fin,x,y); moveship(x,y); end; {處理合並指令} 'C' : begin readln(fin,x,y); checkship(x,y); end; {處理詢問指令} end; end;
close(fin);close(fout); end.
var
father,count,behind:array[1..maxn] of integer; x,y:integer; i,CmdCount:longint; ch:char;
function Find_Father(x:integer):integer; var
i,j,f,next:integer; begin i:=x;
while Father[i]<>i do i:=Father[i]; f:=i; i:=x;
while i<>f do begin
next:=Father[i]; Father[i]:=f;
{calculate Behind} j:=next; repeat
Behind[i]:=Behind[i]+Behind[j]; j:=Father[j]; until Father[j]=j; i:=next; end;
find_Father:=f; end;
procedure MoveShip(x,y:integer); var
fx,fy:integer; begin
fx:=find_Father(x); fy:=find_Father(y); Father[Father[fx]]:=fy;
Behind[fx]:=Behind[fx]+Count[fy]; Count[fy]:=Count[fy]+Count[fx]; end;
procedure CheckShip(x,y:integer); var f1,f2:integer; begin
f1:=Find_Father(x); f2:=Find_Father(y);
if f1<>f2 then writeln(-1) else writeln(abs(Behind[x]-Behind[y])-1); end;
begin
assign(input,'galaxy.in');reset(input); assign(output,'galaxy.ans');rewrite(output); for i:=1 to maxn do
begin father[i]:=i;count[i]:=1;behind[i]:=0; end; readln(CmdCount);
for i:=1 to CmdCount do begin
read(ch); case ch of
'M' : begin readln(x,y); MoveShip(x,y); end; 'C' : begin readln(x,y); CheckShip(x,y); end; end; end;
close(input);close(output); end.