货车运输

P1967 [NOIP2013 提高组] 货车运输 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

  • kur+LCA(树上倍增,并查集,最大生成树)
  • 对于原来的图如果形成了环,那么环上权值最小的是可以舍去的,由此生成一颗最大生成树(kur)
  • f[i][j]代表i的第2j个父节点是谁,w[i][j]代表从第i到第i的第2j个父亲的路程中最小权值是多少,也就是答案(最大承重)
  • dfs用于处理每个点的deep,f[i][0],w[i][0]值,用于后面动态规划求出f,w所有的值,(类似于动态规划问题的初始化过程),其中每个根节点的父亲为他本身,权值为无穷大
  • LCA初始化就是动态规划过程,即i点的第2j个父亲是i点的第2j-1个父亲的第2j-1个父亲,权值为两者中最小的
  • LCA先将深度大的点抬到相同的高度,再两个点同时向根节点推进,知道它们的父亲刚好是同一个点,在推进的过程不断更新最小权值也就是答案
// 4 3
// 1 2 4
// 2 3 3
// 3 1 1
// 3
// 1 3
// 1 4
// 1 3
// https://www.luogu.com.cn/problem/P1967
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define NMAX 10005
#define EMAX 100005
#define INF 1e9
int n, m, q;
bool vis[NMAX];
struct Node1
{
    int u, v, w;
} edge_k[EMAX];
int head[NMAX], idx;
struct Node2
{
    int to, w, nex;
} edge_[EMAX];
void add(int u, int v, int w)
{
    edge_[++idx] = (Node2){v, w, head[u]};
    head[u] = idx;
}
bool cmp(Node1 a, Node1 b)
{
    return a.w > b.w;
}
void input()
{
    cin >> n >> m;
    for (int i = 1; i <= m; i++)
    {
        scanf("%d %d %d", &edge_k[i].u, &edge_k[i].v, &edge_k[i].w);
    }
    cin >> q;
    sort(edge_k + 1, edge_k + 1 + m, cmp);
}
int parent[NMAX];
void init()
{
    for (int i = 1; i <= n; i++)
        parent[i] = i;
}
int fa(int x)
{
    return (x == parent[x]) ? x : parent[x] = fa(parent[x]);
}
void kur()
{
    init();
    for (int i = 1; i <= m; i++)
    {
        int fx = fa(edge_k[i].u), fy = fa(edge_k[i].v);
        if (fx != fy)
        {
            parent[fx] = fy;
            add(edge_k[i].u, edge_k[i].v, edge_k[i].w);
            add(edge_k[i].v, edge_k[i].u, edge_k[i].w);
        }
    }
}
int f[NMAX][21], w[NMAX][21], deep[NMAX];
void dfs(int now)
{
    vis[now] = true;
    for (int i = head[now]; i; i = edge_[i].nex)
    {
        int to = edge_[i].to;
        if (!vis[to])
        {
            f[to][0] = now;
            w[to][0] = edge_[i].w;
            deep[to] = deep[now] + 1;
            vis[to] = true;
            dfs(to);
        }
    }
}

int lca(int x, int y)
{
    if (fa(x) != fa(y))
        return -1;
    if (deep[x] > deep[y])
    {
        swap(x, y);
    }
    int ans = INF;
    for (int i = 20; i >= 0; i--)
    {
        if (deep[f[y][i]] >= deep[x])
        {
            ans = min(ans, w[y][i]);
            y = f[y][i];
        }
    }
    if (x == y)
    {
        return ans;
    }
    for (int i = 20; i >= 0; i--)
    {
        if (f[x][i] != f[y][i])
        {
            ans = min(ans, min(w[x][i], w[y][i]));
            x = f[x][i], y = f[y][i];
        }
    }
    return min(ans, min(w[x][0], w[y][0]));
}
int main()
{
    input();
    kur();
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
        {
            deep[i] = 1;
            dfs(i);
            f[i][0] = i;
            w[i][0] = INF;
        }
    }
    for (int i = 1; i <= 20; i++)
    {
        for (int j = 1; j <= n; j++)
        {
            f[j][i] = f[f[j][i - 1]][i - 1];
            w[j][i] = min(w[j][i - 1], w[f[j][i - 1]][i - 1]);
        }
    }
    for (int i = 1; i <= q; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        printf("%d\n", lca(a, b));
    }
}

 

posted on 2022-08-13 17:00  樵风  阅读(129)  评论(0)    收藏  举报