1. 程式人生 > >NOI2002_ Galaxy銀河英雄傳說86

NOI2002_ Galaxy銀河英雄傳說86

ssi 戰爭 har input output 多個 rewrite 數據類型 bsp

NOI2002_ Galaxy銀河英雄傳說86


公元五八○一年,地球居民遷移至金牛座α第二行星,;宇宙歷七九九年,銀河系的兩大軍事集團在巴米利恩星;楊威利擅長排兵布陣,巧妙運用各種戰術屢次以少勝多;然而,老謀深算的萊因哈特早已在戰略上取得了主動;在楊威利發布指令調動艦隊的同時,萊因哈特為了及時;作為一個資深的高級程序設計員,你被要求編寫程序分;輸入文件;第一行有一個整數t(1?t?500,000),表;m


公元五八○一年,地球居民遷移至金牛座α第二行星,在那裏發表銀河聯邦創立宣言,同年改元為宇宙歷元年,並開始向銀河系深處拓展。

宇宙歷七九九年,銀河系的兩大軍事集團在巴米利恩星域爆發戰爭。泰山壓頂集團派宇宙艦隊司令萊因哈特率領十萬余艘戰艦出征,氣吞山河集團點名將楊威利組織麾下三萬艘戰艦迎敵。

楊威利擅長排兵布陣,巧妙運用各種戰術屢次以少勝多,難免恣生驕氣。在這次決戰中,他將巴米利恩星域戰場劃分成30000列,每列依次編號為1,2,…,30,000。之後,他把自己的戰艦也依次編號為1, 2, …, 30000,讓第i號戰艦處於第i列(i=1, 2, …,30,000),形成“一字長蛇陣”,誘敵深入。這是初始陣形。當進犯之敵到達時,楊威利會多次發布合並指令,將大部分戰艦集中在某幾列上,實施密集攻擊。合並指令為mij,含義為讓第i號戰艦所在的整個戰艦隊列,作為一個整體(頭在前尾在後)接至第j號戰艦所在的戰艦隊列的尾部。顯然戰艦隊列是由處於同一列的一個或多個戰艦組成的。合並指令的執行結果會使隊列增大。

然而,老謀深算的萊因哈特早已在戰略上取得了主動。在交戰中,他可以通過龐大的情報網絡隨時監聽楊威利的艦隊調動指令。

在楊威利發布指令調動艦隊的同時,萊因哈特為了及時了解當前楊威利的戰艦分布情況,也會發出一些詢問指令:cij。該指令意思是,詢問電腦,楊威利的第i號戰艦與第j號戰艦當前是否在同一列中,如果在同一列中,那麽它們之間布置有多少戰艦。

作為一個資深的高級程序設計員,你被要求編寫程序分析楊威利的指令,以及回答萊因哈特的詢問。 最終的決戰已經展開,銀河的歷史又翻過了一頁……

輸入文件

第一行有一個整數t(1?t?500,000),表示總共有T條指令。 以下有T行,每行有一條指令。指令有兩種格式:

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.

NOI2002_ Galaxy銀河英雄傳說86