洛谷 P1967 货车运输

题意简述

给定一张图,求两点最短路径上的点的值的最小值

题解思路

先进行最大生成树,再倍增求lca

代码

#include <cstdio>
#include <algorithm>
struct Edge
{
    int u, v, w;
}e[51000];
int n, m, q, u, v, w, xx, yy, cnt;
int fa[11000];
int h[21000], to[21000], nxt[21000], val[21000];
int lg[21000], dep[21000], f[21000][20][2];
inline bool cmp(const Edge& x, const Edge& y) {return x.w > y.w; }
int find(const int& x) {return x ^ fa[x] ? fa[x] = find(fa[x]) : x; }
inline void add_edge(const int& u, const int& v, const int& w)
{
    to[++cnt] = v;
    val[cnt] = w;
    nxt[cnt] = h[u];
    h[u] = cnt;
}
void dfs(const int& x)
{
    for (register int i = 0; f[x][i][0]; ++i)
    {
        f[x][i + 1][0] = f[f[x][i][0]][i][0];
        f[x][i + 1][1] = std::min(f[x][i][1], f[f[x][i][0]][i][1]);
    }
    for (register int i = h[x]; i; i = nxt[i])
        if (to[i] ^ f[x][0][0])
        {
            dep[to[i]] = dep[x] + 1;
            f[to[i]][0][0] = x;
            f[to[i]][0][1] = val[i];
            dfs(to[i]);
        }
}
inline int lca(int u, int v, int s = 0x3f3f3f3f)
{
    if (dep[u] < dep[v]) std::swap(u, v);
    while (dep[u] > dep[v])
    {
        s = std::min(s, f[u][lg[dep[u] - dep[v]]][1]);
        u = f[u][lg[dep[u] - dep[v]]][0];
    }
    if (u == v) return s;
    for (register int i = lg[dep[u]] + 1; i--; )
        if (f[u][i][0] ^ f[v][i][0])
        {
            s = std::min(s, f[u][i][1]);
            s = std::min(s, f[v][i][1]);
            u = f[u][i][0];
            v = f[v][i][0];
        }
    s = std::min(s, f[u][0][1]);
    s = std::min(s, f[v][0][1]);
    return s;
}
int main()
{
    scanf("%d%d", &n, &m);
    for (register int i = 1; i <= n; ++i) fa[i] = i;
    for (register int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
    for (register int i = 1; i <= m; ++i)
        scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
    std::sort(e + 1, e + m + 1, cmp);
    for (register int i = 1; i <= m; ++i)
    {
        xx = find(e[i].u);
        yy = find(e[i].v);
        if (xx != yy)
        {
            fa[xx] = yy;
            add_edge(e[i].u, e[i].v, e[i].w);
            add_edge(e[i].v, e[i].u, e[i].w);
        }
    }
    for (register int i = 1; i <= n; ++i) if (!dep[i]) dfs(i);
    scanf("%d", &q);
    for (register int i = 1; i <= q; ++i)
    {
        scanf("%d%d", &u, &v);
        if (find(u) != find(v)) printf("-1\n");
        else printf("%d\n", lca(u, v));
    }
}
posted @ 2018-09-24 20:44  xuyixuan  阅读(88)  评论(0编辑  收藏  举报