[codeforces] Gym - 100814C Connecting Graph (並查集+LCA)

[codeforces] Gym - 100814C Connecting Graph (並查集+LCA)

題目鏈接:100814C Connecting Graph
題目大意:
給定n個點, m個操作, 操作由兩種形式
1uvu,v 連一條邊
2uv 詢問u,v 最早什麼時候連通, 如果不連通輸出1
數據範圍:
(1<=n,m<=1e5)

解題思路:
兩個點什麼時候最早連通就是這兩個點之間的最大值, 可以想到用LCA+倍增維護最大值。 題中並沒有說肯定是棵樹, 但是如果兩個點之前已經聯通了, 當前這條邊就沒有必要加進去了(有點最小生成樹的感覺), 所以最後肯定生成的是一個樹。
這道題的主要思想就是用LCA + 倍增維護最大值。

代碼:

/**********************************************
 *Author*        :ZZZZone
 *reated Time*  : 2017/8/8 20:57:14
 *ended  Time*  : 2017/8/9 12:05:21
*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
const int MaxN = 1e5;

int fa[MaxN + 5], dis[MaxN + 5];
int up[MaxN + 5][25], Max[MaxN + 5][25];
vector<PII>edge[MaxN + 5];
struct NODE{
    int p, u, v;
}q[MaxN + 5];
int T, n, m, tot;

void init(){
    for(int i = 1; i<= n; i++) fa[i] = i;
    memset(dis, 0, sizeof(dis));
    memset(up, 0, sizeof(up));
    memset(Max, 0, sizeof(Max));
    memset(edge, 0, sizeof(edge));
    tot = 0;
}

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

void Union(int u, int v){
    int fu = find(u), fv = find(v);
    if(fu != fv) fa[fu] = fv;
}

void dfs(int u){
    /*
    for(int i = 1; i <= 20; i++){
        up[u][i] = up[up[u][i - 1]][i - 1];
        Max[u][i] = max(Max[u][i - 1], Max[up[u][i - 1]][i - 1]);
    }
    */
    for(int i = 0; i < edge[u].size(); i++){
        int v = edge[u][i].first;
        int len = edge[u][i].second;
        if(dis[v] == 0){
            dis[v] = dis[u] + 1;
            Max[v][0] = len;
            up[v][0] = u;
            dfs(v);
        }
    }
}

void init_lca(){
    for(int j = 1; (1 << j) <= n; j++){
        for(int i = 1; i <= n; i++){
            up[i][j] = up[up[i][j - 1]][j - 1];
            Max[i][j] = max(Max[i][j - 1], Max[up[i][j - 1]][j - 1]);
        }
    }
}

int getans(int a, int b){
    if(dis[a] < dis[b]) swap(a, b);
    int c = dis[a] - dis[b], res = 0;
    for(int i = 0; (1 << i) <= n; i++){
        if(c & (1 << i)){
            res = max(res, Max[a][i]);
            a = up[a][i];
        }
    }
    if(a == b) return res;
    for(int i = 20; i >= 0; i--){
        if(up[a][i] != up[b][i]){
            res = max(res, Max[a][i]);
            res = max(res, Max[b][i]);
            a = up[a][i];
            b = up[b][i];
        }
    }
    return max(res, max(Max[a][0], Max[b][0]));
}

int main()
{
    scanf("%d", &T);
    while(T--){
        scanf("%d %d", &n, &m);
        init();
        for(int i = 1; i <= m; i++){
            int x, u, v;
            scanf("%d %d %d", &x, &u, &v);
            if(x == 1){
                int fu = find(u), fv = find(v);
                if(fu == fv) continue;
                fa[fu] = fv;
                edge[u].push_back(make_pair(v, i));
                edge[v].push_back(make_pair(u, i));
            }
            else q[++tot].p = i, q[tot].u = u, q[tot].v = v;
        }
        for(int i  = 1; i <= n; i++)
            if(dis[i] == 0){
                dis[i] = 1;
                dfs(i);
            }
        init_lca();
        for(int i = 1; i<= tot; i++){
            int fu = find(q[i].u), fv = find(q[i].v);
            if(fu != fv) printf("-1\n");
            else {
                int ans = getans(q[i].u, q[i].v);
                if(ans > q[i].p) printf("-1\n");
                else printf("%d\n", ans);
            }
        }
    }
    return 0;
}

在此輸入正文

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