• 洛谷 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
    ");
            else printf("%lld
    ",work(x,y));
        }
        return 0;
    } 
  • 相关阅读:
    23种设计模式
    (C# 基础) 接口
    (C#) Handling and Raising Events
    (C# 基础) 位运算
    (C#) 线程之 AutoResetEvent, EventHandle.
    (C#) 线程基础
    div在固定高的文字垂直居中
    滚动置顶
    jQuery给同一个元素两个点击事件
    (置顶)js实现超过页面一屏后,点击图标滚动到页面顶部top
  • 原文地址:https://www.cnblogs.com/CLGYPYJ/p/7681771.html
Copyright © 2020-2023  润新知