传送门

这道题,先用kruskal求一遍图中的最大生成树。

然后,倍增求lca,求lca的同时求出边权的最小值。

#include <cstring>
#include <cstdio>
#include <algorithm>

int n, m, cnt, q, t, k;
int f[10001], head[100001], p[10001][21], minn[10001][21], deep[10001];
bool vis[10001];
struct node
{
    int x, y, z;
}tree[100001];
struct Node
{
    int next, to, val;
}edge[100001];

inline void add(int a, int b, int c)
{
    edge[cnt].val = c;
    edge[cnt].to = b;
    edge[cnt].next = head[a];
    head[a] = cnt++;
}

inline int father(int a)
{
    return a == f[a] ? a : f[a] = father(f[a]);
}

inline bool cmp(node a, node b)
{
    return a.z > b.z;
}

void kruskal()
{
    int i;
    for(i = 1; i <= m; i++)    scanf("%d %d %d", &tree[i].x, &tree[i].y, &tree[i].z);
    for(i = 1; i <= n; i++) f[i] = i;
    std::sort(tree + 1, tree + m + 1, cmp);
    for(i = 1; i <= m; i++)
    {
        int fa = father(tree[i].x), fb = father(tree[i].y);
        if(fa != fb)
        {
            f[fa] = fb;
            add(tree[i].x, tree[i].y, tree[i].z);
            add(tree[i].y, tree[i].x, tree[i].z);
        }
        if(k == n - 1) break;
    }
}

void dfs(int i)
{
    int j;
    vis[i] = 1;
    for(j = head[i]; j != -1; j = edge[j].next)
     if(!vis[edge[j].to])
     {
         deep[edge[j].to] = deep[i] + 1;
         p[edge[j].to][0] = i;
         minn[edge[j].to][0] = edge[j].val;
         dfs(edge[j].to);
     }
}

void init()
{
    int i, j;
    for(j = 1; (1 << j) <= n; j++)
     for(i = 1; i <= n; i++)
     {
         p[i][j] = p[p[i][j - 1]][j - 1];
         minn[i][j] = std::min(minn[i][j - 1], minn[p[i][j - 1]][j - 1]);
     }
}

int lca(int a, int b)
{
    int i, j, ret = 707406378;
    if(deep[a] < deep[b]) std::swap(a, b);
    for(i = 0; (1 << i) <= deep[a]; i++);
    i--;
    for(j = i; j >= 0; j--)
     if(deep[a] - (1 << j) >= deep[b])
     {
         ret = std::min(ret, minn[a][j]);
         a = p[a][j];
     }
    if(a == b) return ret;
    for(j = i; j >= 0; j--)
     if(p[a][j] != p[b][j])
     {
         ret = std::min(ret, std::min(minn[a][j], minn[b][j]));
         a = p[a][j];
         b = p[b][j];
     }
    ret = std::min(ret, std::min(minn[a][0], minn[b][0]));
    return ret;
}

int main()
{
    int i, j, x1, y1;
    scanf("%d %d", &n, &m);
    memset(head, -1, sizeof(head));
    //memset(minn, 127 / 3, sizeof(minn));
    kruskal();
    for(i = 1; i <= n; i++)
     if(!vis[i])
     {
         deep[i] = 1;
         dfs(i);
     }
    init();
    scanf("%d", &q);
    for(i = 1; i <= q; i++)
    {
        scanf("%d %d", &x1, &y1);
        if(father(x1) != father(y1)) printf("-1\n");
        else printf("%d\n", lca(x1, y1));
     }
    return 0;

}
View Code

相关文章: