1. 程式人生 > >[noi2002]銀河英雄傳說

[noi2002]銀河英雄傳說

傳說 所在 galaxy 格式 連接 是否 div 在那 noi2002

Description

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

Input

輸入文件galaxy.in的第一行有一個整數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是兩個整數(1<=i , j<=30000),表示指令涉及的戰艦編號。該指令是萊因哈特發布的詢問指令。

Output

輸出文件為galaxy.out。你的程序應當依次對輸入的每一條指令進行分析和處理:
如果是楊威利發布的艦隊調動指令,則表示艦隊排列發生了變化,你的程序要註意到這一點,但是不要輸出任何信息;
如果是萊因哈特發布的詢問指令,你的程序要輸出一行,僅包含一個整數,表示在同一列上,第i號戰艦與第j號戰艦之間布置的戰艦數目。如果第i號戰艦與第j號戰艦當前不在同一列上,則輸出-1。

Sample Input

4
M 2 3
C 1 2
M 2 4
C 4 2

Sample Output

-1
1


帶有邊權的並查集問題,詢問中第一個問題沒什麽好說的,重點在於戰艦間距離的詢問;
很明顯我們不能去記錄戰艦的排列順序,這樣就失去了並查集的意義;
既然不能單獨計算,我們就可以考慮在構建並查集的過程中處理戰艦距離;
尋找節點的過程中會不斷找到某節點的父親直至找到根,而"點到根的距離=點到父親的距離+父親到根的距離",因此可以在構建過程中計算此距離;
另外,因為我們只需要考慮某點到根的距離,所以在插入艦隊時,不必記錄艦隊尾部,只需直接連接兩個原艦隊的根,而根到根的距離就等於原艦隊的長度;
詢問時只需取兩點到根的距離差的絕對值-1即可;
AC GET☆DAZE

代碼↓
技術分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
int fa[30039],dis[30039]={0},size[30039];
int fi,fj;
int find(int k)
{
    if(fa[k]==k)
    {
        return k;
    }
    int pre=fa[k];
    fa[k]=find(fa[k]);
    dis[k]+=dis[pre];
    return fa[k];
}
int main()
{
    char com;
    int T,i,j,a;
    scanf("%d",&T);
    for(a=1;a<=30000;a++)
    {
        fa[a]=a;
        size[a]=1;
    }
    while(T--)
    {
        scanf(" %c",&com);
        scanf("%d%d",&i,&j);
        fi=find(i);
        fj=find(j);
        if(com==M)
        {
            dis[fi]=size[fj];
            fa[fi]=fj;
            size[fj]+=size[fi];
        }
        else
        {
            if(fi==fj)
            {
                printf("%d\n",abs(dis[i]-dis[j])-1);
            }
            else
            {
                printf("-1\n");
            }
        }
    }
    return 0;
}
View Code

 

[noi2002]銀河英雄傳說