[NOIP 2013]货车运输

题目传送门

因为要求最长集合线段中的最小值所以果断使用最大生成树,因为给定的是张图,无法确定唯一路径,而在树上就是了

再去求相当于两点分别为端点的链上最小值

以前写过树上路径,详情请点击(T1)

所以这时就成了一道板子题了

注意:这或许不仅仅只有一棵树,遍历找没有访问过的点重新当根即可。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
inline int read()
{
    int f=1,ans=0;char c;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
    return ans*f;
}
int f[10001],n,m;
struct node{
    int u,v,w,nex;
}x[50001];
int head[10001],cnt;
void add(int u,int v,int w)
{
    x[cnt].u=u,x[cnt].v=v,x[cnt].w=w,x[cnt].nex=head[u],head[u]=cnt++;
}
struct node1{
    int a,b,c;
}s[50001];
int sry;
bool cmp(node1 x1,node1 x2)
{
    return x1.c>x2.c;
}
int find(int x)
{
    if(f[x]==x) return x;
    return f[x]=find(f[x]);
}
int fa[10001][21];
int minn[10001][21],deep[10001];
void dfs(int f,int fath)
{  
    fa[f][0]=fath;
    deep[f]=deep[fath]+1;
    for(int i=1;(1<<i)<=deep[f];i++)
    {
        fa[f][i]=fa[fa[f][i-1]][i-1];
        minn[f][i]=min(minn[f][i-1],minn[fa[f][i-1]][i-1]);
    }
    for(int i=head[f];i!=-1;i=x[i].nex)
    {
        if(x[i].v==fath) continue;
        minn[x[i].v][0]=x[i].w;
        dfs(x[i].v,f);
    }
}
int q;
int lca(int u,int v)
{
    if(deep[u]==0||deep[v]==0) return -1;
    if(find(u)!=find(v)) return -1;
    int ans=2<<30-1;
    if(deep[u]<deep[v]) swap(u,v);
    for(int i=20;i>=0;i--)
        if(deep[u]-(1<<i)>=deep[v])
        {
            ans=min(ans,minn[u][i]);
            u=fa[u][i];
        }
    if(u==v)  return ans;
    for(int i=20;i>=0;i--)
    {
        if(fa[u][i]==fa[v][i]) continue;
        ans=min(ans,minn[u][i]),u=fa[u][i];
        ans=min(ans,minn[v][i]),v=fa[v][i]; 
    }
    ans=min(ans,minn[u][0]),u=fa[u][0];
    ans=min(ans,minn[v][0]),v=fa[v][0];
    return ans;
}
int main()
{
    memset(head,-1,sizeof(head));
    n=read(),m=read();
    for(int i=1;i<=n;i++) f[i]=i; 
    for(int i=1;i<=m;i++) s[i].a=read(),s[i].b=read(),s[i].c=read(); 
    sort(s+1,s+m+1,cmp);
    for(int i=1;i<=m;i++)
    {
        int t1=find(s[i].a),t2=find(s[i].b);
        if(t1!=t2)
        {
            f[t2]=t1;
            sry++;
            add(s[i].a,s[i].b,s[i].c),add(s[i].b,s[i].a,s[i].c);
        }
    }
    for(int i=1;i<=n;i++)
    {
        if(deep[i]==0) dfs(i,0);
    } 
    q=read();
    for(int i=1;i<=q;i++)
    {
        int u=read(),v=read();
        printf("%d
",lca(u,v)); 
    }
}
原文地址:https://www.cnblogs.com/si-rui-yang/p/9550099.html