1. 程式人生 > >邊帶權並查集 - 銀河英雄傳說(NOI2002)

邊帶權並查集 - 銀河英雄傳說(NOI2002)

銀河英雄傳說

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

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

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

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

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

作為一個資深的高階程式設計員,你被要求編寫程式分析楊威利的指令,以 及回答萊因哈特的詢問。

最終的決戰已經展開,銀河的歷史又翻過了一頁……

輸入
輸入檔案 galaxy.in 的第一行有一個整數 T(1<=T<=500,000),表示總共有 T 條指令。

以下有 T 行,每行有一條指令。指令有兩種格式:

M i j :i 和 j 是兩個整數(1<=i , j<=30000),表示指令涉及的戰艦編號。
該指令是萊因哈特竊聽到的楊威利釋出的艦隊調動指令,並且保證第 i 號戰 艦與第 j 號戰艦不在同一列。

C i j :i 和 j 是兩個整數(1<=i , j<=30000),表示指令涉及的戰艦編號。
該指令是萊因哈特釋出的詢問指令

輸出
你的程式應當依次對輸入的每一條指令進行分析和 處理:

如果是楊威利釋出的艦隊調動指令,則表示艦隊排列發生了變化,你的程式 要注意到這一點,但是不要輸出任何資訊;

如果是萊因哈特釋出的詢問指令,你的程式要輸出一行,僅包含一個整數,表示在同一列上,第 i 號戰艦與第 j 號戰艦之間佈置的戰艦數目。如果第 i 號戰 艦與第 j 號戰艦當前不在同一列上,則輸出-1。

樣例輸入
4
M 2 3
C 1 2
M 2 4
C 4 2
樣例輸出
-1
1
提示
在這裡插入圖片描述


Analysis

其實也沒有想象中的那麼難嘛
多一個數組d維護每個節點到當前佇列開頭的距離(想象為一顆樹)
然後就在路徑壓縮的時候更新一下,最後答案就是 a b s ( d [ x ] d [ y ] ) 1 abs(d[x]-d[y])-1


話說這種單個字元和數字一起讀入的東西是真的坑。。
最好用 c i n &gt; &gt; cin&gt;&gt; 或者是 s c a n f scanf 讀入字串,反正不要用scanf("%c")
哪怕本機過了,交到虛擬機器上還是會掛


Code

#include<bits/stdc++.h>
#define in read()
#define N 300009
using namespace std;
inline int read(){
	char ch;int f=1,res=0;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
	while(ch>='0'&&ch<='9') {
		res=(res<<3)+(res<<1)+ch-'0';
		ch=getchar();
	}
	return f==1?res:-res;
}
int T,fa[N],d[N],sze[N];
inline int getfa(int x){
	if(x==fa[x]) return x;
	int root=getfa(fa[x]);
	d[x]+=d[fa[x]];
	return fa[x]=root;
}
int main(){
	T=in;int x,y;char ch;
	for(int i=1;i<=30000;++i) fa[i]=i,sze[i]=1; 
	while(T--){
		cin>>ch;x=in;y=in;//字元和數字同時都要讀入的時候要麼用cin,要麼讀字串 
		int fx=getfa(x),fy=getfa(y);
		if(ch=='M'){
			fa[fx]=fy;d[fx]=sze[fy];
			sze[fy]+=sze[fx];
		}
		else{
			if(fx==fy) printf("%d\n",abs(d[x]-d[y])-1);
			else printf("-1\n");
		}
	}
	return 0;
}