BZOJ 4668: 冷戰 並查集

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 440 Solved: 215

Description

1946 年 3 月 5 日,英國前首相溫斯頓·丘吉爾在美國富爾頓發表“鐵
幕演說”,正式拉開了冷戰序幕。
美國和蘇聯同爲世界上的“超級大國”,爲了爭奪世界霸權,兩國及其
盟國展開了數十年的鬥爭。在這段時期,雖然分歧和衝突嚴重,但雙方都
盡力避免世界範圍的大規模戰爭(第三次世界大戰)爆發,其對抗通常通
過局部代理戰爭、科技和軍備競賽、太空競爭、外交競爭等“冷”方式進
行,即“相互遏制,不動武力”,因此稱之爲“冷戰”。
Reddington 是美國的海軍上將。由於戰爭局勢十分緊張,因此他需要
時刻關注着蘇聯的各個活動,避免使自己的國家陷入困境。蘇聯在全球擁
有 N 個軍工廠,但由於規劃不當,一開始這些軍工廠之間是不存在鐵路
的,爲了使武器製造更快,蘇聯決定修建若干條道路使得某些軍工廠聯通。
Reddington 得到了蘇聯的修建日程表,並且他需要時刻關注着某兩個軍工
廠是否聯通,以及最早在修建哪條道路時會聯通。具體而言,現在總共有
M 個操作,操作分爲兩類:
• 0 u v,這次操作蘇聯會修建一條連接 u 號軍工廠及 v 號軍工廠的鐵
路,注意鐵路都是雙向的;
• 1 u v, Reddington 需要知道 u 號軍工廠及 v 號軍工廠最早在加入第
幾條條鐵路後會聯通,假如到這次操作都沒有聯通,則輸出 0;
作爲美國最強科學家, Reddington 需要你幫忙設計一個程序,能滿足
他的要求。

Input

第一行兩個整數 N, M。
接下來 M 行,每行爲 0 u v 或 1 u v 的形式。
數據是經過加密的,對於每次加邊或詢問,真正的 u, v 都等於讀入的
u, v 異或上上一次詢問的答案。一開始這個值爲 0。
1 ≤ N, M ≤ 500000,解密後的 u, v 滿足1 ≤ u, v ≤ N, u不等於v

Output

對於每次 1 操作,輸出 u, v 最早在加入哪條邊後會聯通,若到這個操
作時還沒聯通,則輸出 0。

Sample Input

5 9

0 1 4

1 2 5

0 2 4

0 3 4

1 3 1

0 7 0

0 6 1

0 1 6

1 2 6

Sample Output

0

3

5

HINT

Source


dalao講解

顯然,我們只需要按秩合併就可以了,我們記錄一個size即可,然後查詢這條路徑上的最大值,表示這次操作之後就聯通了

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;

const int MAXN = 500005;
int N, M, fa[MAXN], sz[MAXN], tim[MAXN], timer, opt, u, v, last;

int find( int x ) {
    if( x == fa[x] ) return x;
    else             return find(fa[x]);
}

void add_line( int x, int y ) {
    x = find(x), y = find(y);
    if( x == y ) return;
    else {
        if( sz[x] < sz[y] ) swap( x, y );
        tim[y] = timer;
        sz[x] = sz[x] + sz[y];
        fa[y] = x;
    }
}

int get_dep( int x ) {
    int cnt = 0; 
    while( fa[x] != x ) {
        x = fa[x];
        cnt++;
    }
    return cnt;
}

void query( int x, int y ) {
    int fax = find(x), fay = find(y);
    if( fax != fay ) { printf( "0\n" ); last = 0; return; }
    int depx = get_dep(x), depy = get_dep(y);
    if( depx < depy ) {
        swap( x, y ); 
        swap( depx, depy );
    }
    int tmp = 0;
    while( depx != depy ) {
        if( tmp < tim[x]) tmp = tim[x];
        depx--; x = fa[x];
    } 
    while( x != y ) {
        if( tmp < tim[x] ) tmp = tim[x];
        if( tmp < tim[y] ) tmp = tim[y];
        x = fa[x]; y = fa[y];
    }
    printf( "%d\n", tmp );
    last = tmp;
}

int main( ) {
    scanf( "%d%d", &N, &M );  last = 0;
    for( register int i = 1; i <= N; i++ ) sz[i] = 1;
    for( register int i = 1; i <= N; i++ ) fa[i] = i; 
    for( register int i = 1; i <= M; i++ ) {
        scanf( "%d%d%d", &opt, &u, &v );
        u = u ^ last, v = v ^ last;
        if( opt == 0 ) { timer++; add_line( u, v ); }
        else           query( u, v ); 
    }
    return 0;
}

這裏寫圖片描述

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