洛谷 P1967 货车运输

https://www.luogu.org/problem/show?pid=1967

思路:

  先生成一颗最大生成树,然后走LCA,这过程一直取min。

  在这过程中要重新构图(建一颗树)记录其第2^i的父节点,和这段路径中的最小边。

  当然最重要的是LCA,写的不熟练。

 

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
using namespace std;
const int N=1009;
long long  n,m,q;
struct node{
    long long x,y,z;
}E[50*N];
long long  h[N*10],nex[50*N],to[50*N],cnt,w[50*N];
long long  f[N*10];
long long  deep[N*10],f1[N*10][50],f2[N*10][50],dad[N*10];
bool cmp(node a,node b)
{return a.z>b.z;};
long long  find(long long x)
{
    while(x!=f[x])
    x=f[x]=f[f[x]];
    return x;
}
void build(int x)
{
    for(int i=h[x];i;i=nex[i])
    {
        if(to[i]==dad[x])    continue;
        dad[to[i]]=x;
        f1[to[i]][0]=x;
        f2[to[i]][0]=w[i];
        deep[to[i]]=deep[x]+1;
        build(to[i]);
    }
}
long long work(long long s,long long e)
{
    long long ans=2100000000;
    if(deep[s]<deep[e])
    {
        long long c=e;
        e=s;
        s=c;
    }   
    for (long long i=16;i>=0;--i)
    if (f1[s][i]!=0&&deep[f1[s][i]]>=deep[e])
    {
        ans=min(ans,f2[s][i]);
        s=f1[s][i];
    }     
    if (s==e)
        return ans;
    for (long long i=16;i>=0;--i)
    {
        if (f1[s][i]!=f1[e][i])
        {
            ans=min(min(f2[s][i],f2[e][i]),ans);
            s=f1[s][i];
            e=f1[e][i];    
        }
    }
    ans=min(min(f2[s][0],f2[e][0]),ans);    
    return ans;
}
void Add(int f,int too,int ww)
{
    to[++cnt]=too,nex[cnt]=h[f];h[f]=cnt;w[cnt]=ww;
    to[++cnt]=f,nex[cnt]=h[too],h[too]=cnt;w[cnt]=ww;
} 
int main()//最大生成树 
{
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++)    f[i]=i;
    for(int i=1,z,x,y;i<=m;i++)
    {
        scanf("%lld%lld%lld",&E[i].x,&E[i].y,&E[i].z);    
    }
    sort(E+1,E+1+m,cmp);
    for(int i=1;i<=m;i++)
    {
        int f1=find(E[i].x),f2=find(E[i].y);
        if(f1==f2)    continue;    
        f[f2]=f1;        
        Add(E[i].x,E[i].y,E[i].z);        
    }    
    for(int i=1;i<=n;i++)
    if(f[i]==i)
    {
        dad[i]=i;
        deep[i]=1;
        build(i);
    }
    for(int i=1;i<=16;i++)
        for(int j=1;j<=n;j++)
        {
            f1[j][i]=f1[f1[j][i-1]][i-1];
            f2[j][i]=min(f2[j][i-1],f2[f1[j][i-1]][i-1]);
        }
    long long q,x,y;
    cin>>q;
    for(int i=1;i<=q;i++)
    {
        scanf("%lld%lld",&x,&y);
        if(find(x)!=find(y))
            printf("-1\n");
        else printf("%lld\n",work(x,y));
    }
    return 0;
} 

 

posted @ 2017-10-17 15:11  浪矢-CL  阅读(92)  评论(0编辑  收藏  举报