zoukankan      html  css  js  c++  java
  • 【luogu P1967货车运输】题解

    【货车运输】

    题目要求的是求出点x到点y能运输的最大货物量,换句话说就是找到x到y的一条路径,使最小边权值尽可能大。

    第一眼想到用类似最短路的方法,但是数据范围太大,如果个x,y都跑一遍最短路显然会超时。

    其实不难发现,我们只需要选择尽可能大的边,让他们组成一颗颗最大生成树,保证了原来图的联通性,又把一张图退化成树。

    边权最小的值在倍增的过程中顺便处理,时间复杂度O(q*logn)

    代码有点长,但都是模板

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #define N 1000000
    #define maxint 0x7f7f7f7f
    using namespace std;
    int n,m,q,tot;
    int fir[N],to[N],nex[N],dis[N];
    int fa[N],f[N][25],deep[N],d[N][25];
    bool vis[N];
    struct node{
        int x,y,k;
    }e[N];
    inline void r(int &x){
        x=0;
        char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
    }
    inline void add(int x,int y,int k){//树上的无向边建立
        to[++tot]=y,nex[tot]=fir[x],dis[tot]=k,fir[x]=tot;
        to[++tot]=x,nex[tot]=fir[y],dis[tot]=k,fir[y]=tot;
    }
    inline bool cmp(node x,node y){//边权按大到小排序
        return x.k>y.k;
    }
    inline int anc(int x){//路径压缩
        if(fa[x]!=x) fa[x]=anc(fa[x]);
        return fa[x];
    }
    inline int dfs(int x){//搜索树,记录f[][0]
        vis[x]=1;
        int i,v;
        for(i=fir[x];v=to[i],i;i=nex[i]){
            if(!vis[v]){
                deep[v]=deep[x]+1;
                f[v][0]=x;
                d[v][0]=dis[i];
                dfs(v);
            }
        }
    }
    inline void cal(){//倍增,求出每个节点的祖先,以及每个节点到祖先的路径上最小边权
        for(int i=1;i<=19;i++)
            for(int j=1;j<=n;j++){
                f[j][i]=f[f[j][i-1]][i-1];
                d[j][i]=min(d[j][i-1],d[f[j][i-1]][i-1]);//最小边权用d记录
            }
    }
    inline int lca(int x,int y){//求答案
        if(f[x][19]!=f[y][19])//如果不等,那么他们不在一棵树上
            return -1;
        int i,ans=maxint;
        if(deep[x]<deep[y]) swap(x,y);//以下lca模板,在求lca过程顺便更新an最小值
        for(i=19;i>=0;i--){
            if(deep[f[x][i]]>=deep[y]){
                ans=min(ans,d[x][i]);
                x=f[x][i];
            }
            if(x==y) return ans;
        }
        for(i=19;i>=0;i--)
            if(f[x][i]!=f[y][i]){
                ans=min(ans,min(d[x][i],d[y][i]));
                x=f[x][i];
                y=f[y][i];
            }
        ans=min(ans,min(d[x][0],d[y][0]));
        return ans;
    }
    int main()
    {
        int i,j,x,y,k,a,b;
        r(n),r(m);
        for(i=1;i<=m;i++)
            r(e[i].x),r(e[i].y),r(e[i].k);
        sort(e+1,e+1+m,cmp);
        for(i=1;i<=n;i++) fa[i]=i;
        for(i=1;i<=m;i++){//最大生成树模板
            a=anc(e[i].x),b=anc(e[i].y);
            if(a==b) continue;
            add(e[i].x,e[i].y,e[i].k);
            fa[a]=b;
        }
        for(i=1;i<=n;i++){
            if(!vis[i]){//因为可能有多棵树,因此要遍历每个点,看看它是否在已遍历的树上
                f[i][0]=i;
                d[i][0]=maxint;
                deep[i]=1;
                dfs(i);
            }
        }
        cal();
        r(q);
        while(q--){
            r(x),r(y);
            printf("%d
    ",lca(x,y));
        }
    }
  • 相关阅读:
    http
    VUE-1
    AJAX
    html常用标签
    CSS网页布局
    概念整理3
    SEO
    概念整理2
    var
    概念整理
  • 原文地址:https://www.cnblogs.com/quitter/p/11497017.html
Copyright © 2011-2022 走看看