1. 程式人生 > >(倍增lca)P1967 貨車運輸

(倍增lca)P1967 貨車運輸

https://www.luogu.org/problemnew/show/P1967
A國有n n座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物, 司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。
輸入格式:
第一行有兩個用一個空格隔開的整數 n,m 表示 A 國有 n 座城市和 m 條道路。
接下來 m行每行 3 3個整數 x, y, z,每兩個整數之間用一個空格隔開,表示從 x號城市到 y號城市有一條限重為 z 的道路。注意: x 不等於 y,兩座城市之間可能有多條道路 。
接下來一行有一個整數 q,表示有 q 輛貨車需要運貨。
接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車需要從 x 城市運輸貨物到 y 城市,注意: x 不等於 y 。
輸出格式:
共有 q 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。如果貨車不能到達目的地,輸出-1。

為了取得最大流量路徑,每兩個結點之間的路徑是一定的,我們只需要找出這條路徑便可以得到答案,其多餘的路徑是無效的,首先跑出原圖的最大生成樹,用lca處理查詢問題。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e4 + 10;
const int maxm = 5e4 + 10;
const int INF = 0x3f3f3f3f;
int pre[maxn];
int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); }
struct Krustral
{
    int u, v, w;
    bool operator<(const Krustral &a) const
    {
        return w > a.w;
    }
} krus[maxm];
vector<pair<int, int>> E[maxn];
int dep[maxn], trefa[maxn][21], wet[maxn][21], vis[maxn];
void dfs(int u)
{
    vis[u] = 1;
    for (pair<int, int> x : E[u])
    {
        if (vis[x.first])
            continue;
        dep[x.first] = dep[u] + 1;
        trefa[x.first][0] = u;
        wet[x.first][0] = x.second;
        dfs(x.first);
    }
}
int lca(int x, int y)
{
    if (find(x) != find(y))
        return -1;
    int ans = INF;
    if (dep[x] > dep[y])
        swap(x, y);
    register int i;
    for (i = 20; i >= 0; i--)
    {
        if (dep[trefa[y][i]] >= dep[x]) //使x,y同一深度
        {
            ans = min(ans, wet[y][i]);
            y = trefa[y][i];
        }
    }
    if (x == y)
        return ans;
    for (i = 20; i >= 0; i--) //兩個結點一起向上走
    {
        if (trefa[x][i] != trefa[y][i])
        {
            ans = min(ans, min(wet[x][i], wet[y][i]));
            x = trefa[x][i];
            y = trefa[y][i];
        }
    }
    ans = min(ans, min(wet[x][0], wet[y][0]));
    return ans;
}
int main()
{
    int n, m, q, x, y, z;
    scanf("%d%d", &n, &m);
    register int i, j;
    for (i = 1; i <= n; i++)
        pre[i] = i;
    for (i = 0; i < m; i++)
    {
        scanf("%d%d%d", &x, &y, &z);
        krus[i].u = x, krus[i].v = y, krus[i].w = z;
    }
    sort(krus, krus + m);
    int cnt = 0;
    for (i = 0; i < m; i++)
    {
        x = krus[i].u, y = krus[i].v, z = krus[i].w;
        if (find(x) != find(y))
        {
            E[x].emplace_back(make_pair(y, z));
            E[y].emplace_back(make_pair(x, z));
            pre[find(x)] = find(y);
            if (cnt++ == n - 1)
                break;
        }
    }
    for (i = 1; i <= n; i++)
    {
        if (vis[i])
            continue;
        dep[i] = 1; //根節點初始化
        dfs(i);
        trefa[i][0] = i;
        wet[i][0] = INF;
    }
    for (i = 1; i <= 20; i++) //初始化
    {
        for (j = 1; j <= n; j++)
        {
            trefa[j][i] = trefa[trefa[j][i - 1]][i - 1];
            wet[j][i] = min(wet[j][i - 1], wet[trefa[j][i - 1]][i - 1]);
        }
    }
    scanf("%d", &q);
    while (q--)
    {
        scanf("%d%d", &x, &y);
        printf("%d\n", lca(x, y));
    }
    // system("pause");
}