P1967 货车运输

  一道最大生成树和LCA的结合问题。

  有几个要注意的:

    1.链式前向星不能直接排序,只能借助另一个结构体完成(详细见代码)

    2.par,fa,w都要处理,其中par可以一开始就处理,而fa在dfs中处理,而w跟着fa一起更新即可。

  剩下的就没什么了……

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define maxn 100005
#define INF 9999999
struct first
{
    int x,y,z;
} fir[5*maxn];
struct second
{
    int to,nxt,w;
} now[5*maxn];
int head[maxn],dep[maxn],par[maxn],fa[maxn][21],w[maxn][21];
int cnt,n,m,q;
bool vis[maxn];
bool cmp(first a,first b)
{
    return a.z>b.z;
}
void Deal_first()
{
    sort(fir+1,fir+1+m,cmp);
    for(int i=1; i<=n; i++)
        par[i]=i;
}
void add(int a,int b,int c)
{
    now[++cnt].to=b;
    now[cnt].nxt=head[a];
    head[a]=cnt;
    now[cnt].w=c;
}
void dfs(int u,int father)
{
    for(int i = 1;i <= 20;i++)
         fa[u][i] = fa[fa[u][i - 1]][i - 1],w[u][i] = min(w[u][i - 1],w[fa[u][i - 1]][i - 1]);//只能这么表示,总不能w[u][i]=w[u][i]吧; 
    for(int i=head[u]; i; i=now[i].nxt)
    {
        int to = now[i].to;
        if(vis[to])
            continue;
        dep[to] = dep[u] + 1;
        vis[to] = 1;
        fa[to][0] = u;
        w[to][0]=now[i].w;
        dfs(to,u);
    }
    return ;
}
int find(int x)
{
    return par[x] == x ? x : par[x] = find(par[x]);
}
void kruskal()
{
    for(int i=1; i<=m; i++)
    {
        int u = fir[i].x,v = fir[i].y,w = fir[i].z;
        if(find(u) == find(v))
            continue;
        par[find(u)]=find(v);
        add(u,v,w);
        add(v,u,w);
    }
    return ;
}
int lca(int x,int y)
{
    if(find(x)!=find(y))
        return -1;
    int ans=INF;
    if(dep[x]<dep[y])
        swap(x,y);
    for(int i=20; i>=0; i--)
    {
        if(dep[fa[x][i]]>=dep[y])
        {
            ans=min(ans,w[x][i]);
            x=fa[x][i];
        }
        if(x==y)
            return ans;
    }
    for(int i=20; i>=0; i--)
    {
        if(fa[x][i]!=fa[y][i])
        {
            ans=min(min(w[x][i],w[y][i]),ans);
            x=fa[x][i];
            y=fa[y][i];
        }
    }
    ans=min(ans,min(w[x][0],w[y][0]));
    return ans;
}
int main()
{
    int x,y,z;
    memset(w,0x3f,sizeof(w));
    scanf("%d%d",&n,&m);
    for(int i=1; i<=m; i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        fir[i].x=x;
        fir[i].y=y;
        fir[i].z=z;
    }
    Deal_first();
    kruskal();
    for(int i=1; i<=n; i++)
        if(!vis[i])
        {
            vis[i] = 1;
            dfs(i,0);
        }
    scanf("%d",&q);
    for(int i=1; i<=q; i++)
    {
        scanf("%d%d",&x,&y);
        printf("%d
",lca(x,y));
    }
    return 0;
}

  最后希望这个题解能帮到大家>\<~~~

原文地址:https://www.cnblogs.com/popo-black-cat/p/10046330.html