(倍增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");
}

猜你喜欢

转载自blog.csdn.net/weixin_40588429/article/details/84202471