• NOIP 2013 货车运输


    货车运输

    描述

    A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

    格式

    输入格式

    第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。

    接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。

    接下来一行有一个整数 q,表示有 q 辆货车需要运货。

    接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

    输出格式

    输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

    样例1

    样例输入1

    4 3 
    1 2 4 
    2 3 3 
    3 1 1 
    3
    1 3 
    1 4 
    1 3
    
    

    样例输出1

    3
    -1
    3
    
    

    限制

    每个测试点1s。

    提示

    对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000; 
    对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000; 
    对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

    来源

    NOIP 2013 提高组 Day 1

    来自hzwer

    这是一个求瓶颈路的问题首先对于30%的数据可以使用暴力,直接一个spfa算法,不断更新到每个结点的瓶颈路这是一个经典的问题,我们发现,最优解一定是在原图的最大生成森林上

    因为不在最大生成森林上的路径一定是更劣的

    那么如果我们只拿出最大生成森林做spfa的话,边的大小降为n,可以通过60%的数据

    其实本题是模板题,询问森林中两个点的路径上的最小边权,连通性用并查集判一下

    可以用树上倍增在logn的复杂度解决一棵树内的一次询问

    预处理F(i,j)表示第i个点距离为2^j的祖先,这个可以深搜整棵树再递推一下,复杂度nlogn

    G(i,j)表示第i个点到其距离为2^j的祖先上的最小权值,然后用倍增的思想俩个点往上跳一跳更新答案就行辣

    #include <bits/stdc++.h>
    #define ll long long
    #define inf 100000000
    #define eps 1e-7
    using namespace std;
    inline int read(){
        int x=0;int f=1;char ch=getchar();
        while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    const int MAXN=1e6+10;
    struct node{
        int v,y,next;
    }e[MAXN];
    struct edge{
        int x,y,v;
    }a[MAXN];
    int linkk[MAXN],len=0,n,m,fa[MAXN],f[MAXN][30],d[MAXN][30],vis[MAXN],ans,dep[MAXN];
    inline void insert(int xx,int yy,int vv){
        e[++len].y=yy;e[len].next=linkk[xx];e[len].v=vv;linkk[xx]=len;
    }
    inline bool mycmp(edge n,edge m){
        return n.v>m.v;
    }
    inline int find(int xx){
        return xx==fa[xx]?xx:fa[xx]=find(fa[xx]);
    }
    namespace zhangenming{
        inline void kruskal(){
            for(int i=1;i<=n;i++){
                fa[i]=i;
            }
            for(int i=1;i<=m;i++){
                int xx=a[i].x;int yy=a[i].y;
                int fx=find(xx);int fy=find(yy);
                if(fx!=fy){
                    fa[fx]=fy;insert(a[i].x,a[i].y,a[i].v),insert(a[i].y,a[i].x,a[i].v);
                }
            }
        }
        inline void dfs(int st,int father){
            f[st][0]=father;dep[st]=dep[father]+1;
            vis[st]=1;
            for(int i=linkk[st];i;i=e[i].next){
                if(!vis[e[i].y]){
                    d[e[i].y][0]=e[i].v;
                    dfs(e[i].y,st);
                }
            }
        }
        void init(){
            n=read();m=read();
            for(int i=1;i<=m;i++){
               a[i].x=read();a[i].y=read();a[i].v=read();        
            }
            sort(a+1,a+m+1,mycmp);
        }
        void getanser(){
            for(int i=1;i<=25;i++){
                for(int j=1;j<=n;j++){
                    if(f[j][i-1]){
                        d[j][i]=min(d[j][i-1],d[f[j][i-1]][i-1]);
                        f[j][i]=f[f[j][i-1]][i-1];
                    }
                }
            }
        }
        inline void LCA(int xx,int yy){
            if(xx==yy) return;
            if(dep[xx]<dep[yy]) swap(xx,yy);
            for(int i=25;i>=0;i--){
                if(dep[xx]-(1<<i)>=dep[yy]) ans=min(ans,d[xx][i]),xx=f[xx][i];
            }
            if(xx==yy) return;
            for(int i=25;i>=0;i--){
                if(f[xx][i]!=f[yy][i]&&f[xx][i]){
                    ans=min(ans,d[xx][i]);ans=min(ans,d[yy][i]);
                    xx=f[xx][i];yy=f[yy][i];
                }
            }
            ans=min(ans,d[xx][0]);ans=min(ans,d[yy][0]);
        }
        void solve(){
            kruskal();
            memset(d,10,sizeof(f));
            for(int i=1;i<=n;i++){
                if(!vis[i]) dfs(i,0);
            }
            getanser();    
            int T=read();
            while(T--){
                int xx=read();int yy=read();
                ans=inf;
                if(find(xx)!=find(yy)){
                    printf("-1
    ");
                }
                else{
                    LCA(xx,yy);
                    printf("%d
    ",ans);
                }
            }
        }
    }
    int main(){
        using namespace zhangenming;
        init();
        solve();
        return 0;
    }
    

      

  • 相关阅读:
    关于加法的类型转换
    设备事件
    html5 事件
    【环境安装】快速安转TensorFlow
    JApiDocs API文档-超级好用
    Docker(超级详细)
    SpringBoot整合Swagger
    Jenkins +Docker+Git 实现自动部署
    Git commit规范
    java支付宝生成二维码
  • 原文地址:https://www.cnblogs.com/something-for-nothing/p/8087311.html
Copyright © 2020-2023  润新知