COGS 260. [NOI2002] 銀河英雄傳說 解題報告

260. [NOI2002] 銀河英雄傳說

【問題描述】

    公元五八○一年,地球居民遷移至金牛座α第二行星,在那裏發表銀河聯邦創立宣言,同年改元爲宇宙曆元年,並開始向銀河系深處拓展。
    宇宙歷七九九年,銀河系的兩大軍事集團在巴米利恩星域爆發戰爭。泰山壓頂集團派宇宙艦隊司令萊因哈特率領十萬餘艘戰艦出征,氣吞山河集團點名將楊威利組織麾下三萬艘戰艦迎敵。
    楊威利擅長排兵佈陣,巧妙運用各種戰術屢次以少勝多,難免恣生驕氣。在這次決戰中,他將巴米利恩星域戰場劃分成30000列,每列依次編號爲1, 2, …, 30000。之後,他把自己的戰艦也依次編號爲1, 2, …, 30000,讓第i號戰艦處於第i列(i = 1, 2, …, 30000),形成“一字長蛇陣”,誘敵深入。這是初始陣形。當進犯之敵到達時,楊威利會多次發佈合併指令,將大部分戰艦集中在某幾列上,實施密集攻擊。合併指令爲M i j,含義爲讓第i號戰艦所在的整個戰艦隊列,作爲一個整體(頭在前尾在後)接至第j號戰艦所在的戰艦隊列的尾部。顯然戰艦隊列是由處於同一列的一個或多個戰艦組成的。合併指令的執行結果會使隊列增大。
    然而,老謀深算的萊因哈特早已在戰略上取得了主動。在交戰中,他可以通過龐大的情報網絡隨時監聽楊威利的艦隊調動指令。
    在楊威利發佈指令調動艦隊的同時,萊因哈特爲了及時瞭解當前楊威利的戰艦分佈情況,也會發出一些詢問指令:C i j。該指令意思是,詢問電腦,楊威利的第i號戰艦與第j號戰艦當前是否在同一列中,如果在同一列中,那麼它們之間佈置有多少戰艦。
    作爲一個資深的高級程序設計員,你被要求編寫程序分析楊威利的指令,以及回答萊因哈特的詢問。
    最終的決戰已經展開,銀河的歷史又翻過了一頁……

    楊威利的指令:並;萊因哈特的詢問:查;戰艦隊列:集。

    並查集+維護隊列長度+前綴和維護距離數組
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int maxn=30000+10;
int p[maxn],sum[maxn],cnt[maxn];//sum:distance to root; cnt:count of queue

int find(int x){
	if(p[x]==x)return x;
	int px=find(p[x]);//真惡毒,要先尋根,不然WA(原因是路徑壓縮前後到祖先的距離不一樣) 
	sum[x]+=sum[p[x]];//維護到根的長度前綴和:子節點到根節點的距離+=它祖先到根節點的距離
	return p[x]=px;
}
void Union(int x,int y){//並集和維護 
	int px=find(x),py=find(y);
	if(px==py)return;
	else p[px]=py;
	sum[px]+=cnt[py];//到根節點的距離+=隊列戰艦數目 
	cnt[py]+=cnt[px];//隊列合併,數目增加 
}
int Ask(int x,int y){
	int px=find(x),py=find(y);
	if(px!=py)return -1;//不在一列 
	else return abs(sum[x]-sum[y])-1;//距離 
}
int main()
{
	#ifndef DEBUG
		string FileName="galaxy";
		freopen((FileName+".in").c_str(),"r",stdin);
		freopen((FileName+".out").c_str(),"w",stdout);
	#endif
	int T;
	scanf("%d",&T);
	for(int i=1;i<=30000;i++)p[i]=i,cnt[i]=1;//每列戰艦的數目初始爲1,根節點是它自己
	while(T--){
		int x,y;
		char s[20];
		scanf("%s%d%d",s,&x,&y);
		if(s[0]=='M')Union(x,y);	
		else printf("%d\n",Ask(x,y));
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章