noip提高组2013 货车运输(luogu 1967)

原题链接:https://www.luogu.org/problem/show?pid=1967

对于这个题,需要用到一些最小生成树的一些性质。

对于一个图的任意两棵最小生成树,每条边的权值都是一一对应的。

对于一个图的所有生成树,任意两点之间的路径(每棵树上唯一确定),最小生成树上,最长的边最短。

最大生成树反之亦然。任意两点之间,最短的边最长。

此题为双向图,在边权问题上,与无向图没什么区别。。。

于是对于每一组询问的两个节点,求出他们的LCA,保存两个点分别走到LCA时的边权最小的权值。

如果两个点不在同一棵树内,当然不会有LCA。

然后就是LCA板子啥的了,蒟蒻码力太弱,写了好长。。。

#include<cstdio>
#include<cstring> 
#include<algorithm>
using namespace std;
void read(int &y)//快速读入 
{
    y=0;char x=getchar();
    while(x<'0'||x>'9') x=getchar();
    while(x>='0'&&x<='9')
    {
        y=y*10+x-'0';
        x=getchar();
    }
}
struct edge
{
    int u,v,w;
}e[50005];
bool cmp(edge x,edge y)//最大生成树边权可从大到小排序 
{
    return x.w>y.w;
} 
int n,m,q,cnt;
int head[20005],nxt[20005],to[20005],d[20005],f[10005],dep[10005];
int fa[10005][25],minv[10005][25];
void add(int u,int v,int w)//邻接表存边 
{
    to[cnt]=v;
    d[cnt]=w;
    nxt[cnt]=head[u];
    head[u]=cnt++;
}
int find(int x)//并查集 
{
    if(x==f[x]) return x;
    return f[x]=find(f[x]);
}
void dfs(int x,int y)//dfs找出每个点的深度 
{
    for(int i=head[x];i!=-1;i=nxt[i])
    {
        if(i!=y)
        {
            dep[to[i]]=dep[x]+1;
            fa[to[i]][0]=x;
            minv[to[i]][0]=d[i];
            dfs(to[i],i^1);
        }
    }
}
int lca(int x,int y)//LCA
{
    if(dep[x]>dep[y])
    {
        int t=x;
        x=y;
        y=t;
    }
    int ans=(1<<30);
    for(int i=15;i>=0;i--)
    {
        if(dep[fa[y][i]]>=dep[x])
        {
            ans=min(ans,minv[y][i]);
            y=fa[y][i];
        }
    }
    if(x==y) return ans;
    for(int i=15;i>=0;i--)
    {
        if(fa[x][i]!=fa[y][i])
        {  
            ans=min(ans,min(minv[x][i],minv[y][i]));  
            x=fa[x][i];  
            y=fa[y][i];  
        }
    }
    return fa[x][0]==0 ? -1 : min(ans,min(minv[x][0],minv[y][0]));
}
int main()
{
    read(n);read(m);
    int u,v,w;
    for(int i=0;i<m;i++)
    {
        read(e[i].u);read(e[i].v);read(e[i].w);
    }
    memset(head,-1,sizeof(head));
    sort(e,e+m,cmp);
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=0;i<m;i++)
    {
        if(find(e[i].u)!=find(e[i].v))
        {
            add(e[i].u,e[i].v,e[i].w);
            add(e[i].v,e[i].u,e[i].w);
            f[find(e[i].u)]=find(e[i].v);
        }
    }
    dep[1]=1;dfs(1,-1);
    for(int j=1;j<=15;j++)
    {
        for(int i=1;i<=n;i++)
        {
            fa[i][j]=fa[fa[i][j-1]][j-1];
            minv[i][j]=min(minv[i][j-1],minv[fa[i][j-1]][j-1]);
        }
    }
    int q,x,y;read(q);
    for(register int i=0;i<q;i++)
    {
        read(x);read(y);
        printf("%d
",lca(x,y));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zeroform/p/7545238.html