• 货车运输(最大生成树+倍增LCA)


    看到第一篇题解的神奇码风……我决定发一篇码风正常的题解造福人类

    这题的做法也非常经典,最大生成树(+LCA),相当于先贪心一下,在LCA的时候记录一下当前最小的边权

    顺便吐槽一下最后一个测试点:

    testdata.in
    7 8
    1 2 2
    1 3 5
    3 4 4
    4 4 2
    3 5 3
    6 7 4
    1 3 3
    4 5 8
    8
    1 2 
    1 4 
    1 3 
    1 5 
    1 6 
    2 5 
    3 5 
    6 7
    testdata.out
    2
    4
    5
    4
    -1
    2
    4
    4
    

    回到题面:注意: (x)不等于(y)两座城市之间可能有多条道路

    虽然(Kruskal)不会挂掉……但是出题人造数据真不严谨

    (Code Below:)

    #include <bits/stdc++.h>
    #define INF 99999999
    using namespace std;
    const int maxn=10000+10;
    const int maxm=50000+10;
    int n,m,q,head[maxn],f[maxn],tot;
    //如题目所示,存储链式前向星和并查集
    int fa[maxn][16],w[maxn][16],dep[maxn],rt,t;
    //fa[i][j]表示第i个结点向上跳2^i个结点,dep[i]存储第i个结点的深度
    struct Edge{
        int x,y,w;
    }e[maxm];
    struct node{
        int to,next,val;
    }tree[maxm<<1];
    inline bool cmp(Edge a,Edge b){//cmp
        return a.w>b.w;
    }
    inline int read(){//读入优化
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void swap(int &a,int &b){int t=a;a=b;b=t;}//交换
    inline void add(int x,int y,int w){//存边
        tree[++tot].to=y;
        tree[tot].val=w;
        tree[tot].next=head[x];
        head[x]=tot;
    }
    int find(int x){//并查集
        if(x!=f[x])
            f[x]=find(f[x]);
        return f[x];
    }
    inline void Kruskal(){//最大生成树
        for(int i=1;i<=n;i++)
            f[i]=i;
        sort(e+1,e+m+1,cmp);
        int ans=0;
        for(int i=1;i<=m;i++){
            int a=find(e[i].x),b=find(e[i].y);
            if(a!=b){
                f[a]=b;ans++;
                add(e[i].x,e[i].y,e[i].w);
                add(e[i].y,e[i].x,e[i].w);
            }
        }
    }
    void dfs(int x,int pre,int val){//LCA预处理
        dep[x]=dep[pre]+1;
        w[x][0]=val;
        fa[x][0]=pre;
        for(int i=1;i<=t;i++){
            fa[x][i]=fa[fa[x][i-1]][i-1];
            w[x][i]=min(w[x][i-1],w[fa[x][i-1]][i-1]);
        }
        for(int i=head[x];i;i=tree[i].next){
            if(tree[i].to!=pre){
                dfs(tree[i].to,x,tree[i].val);
            }
        }
    }
    inline int LCA(int x,int y){//倍增LCA
        if(dep[x]<dep[y]) swap(x,y);
        int ans=INF;
        for(int i=t;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=t;i>=0;i--)
            if(fa[x][i]!=fa[y][i]){
                ans=min(ans,min(w[x][i],w[y][i]));
                x=fa[x][i],y=fa[y][i];
            }
        int val=w[x][0];
        if(fa[x][0]!=y) val=min(val,w[y][0]);
        return min(ans,val);
    }
    
    int main()
    {
        memset(fa,INF,sizeof(fa));
        memset(w,INF,sizeof(w));
        n=read(),m=read();t=log2(n)+1;
        for(int i=1;i<=m;i++){
            e[i].x=read(),e[i].y=read(),e[i].w=read();
        }
        Kruskal();
        //记住!数据不一定联通!图是一个森林!
        for(int i=1;i<=n;i++)
            if(i==f[i])
                dfs(i,i,INF);
        scanf("%d",&q);
        while(q--){
            int x=read(),y=read();
            //printf("%d %d
    ",find(x),find(y));
            if(find(x)!=find(y)) printf("-1
    ");
            else printf("%d
    ",LCA(x,y));
        }
        return 0;
    }
    
  • 相关阅读:
    《百闻牌》
    unity插件开发:dos(cmd)命令输入窗口
    Unity插件开发:使用ScriptedImporter优化Lua文件导入
    崩坏3 渲染分析和PBR展示
    Unity插件开发:SerializedObject/SerializedProperty——查找引用的资源
    Unity插件开发:PrefabUtility(二)--Prefab实例批量Apply
    ml-agent v0.3 win10安装和实践
    Unity文件、文件引用、meta详解
    Unity开发:开启Unity项目中VS工程的属性面板
    Unity宏+RSP文件定义宏
  • 原文地址:https://www.cnblogs.com/owencodeisking/p/9528042.html
Copyright © 2020-2023  润新知