zoukankan      html  css  js  c++  java
  • 【13NOIP提高组】货车运输(洛谷P1967)(Acwing.506)(一本通1877)

    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。

    【输入样例】

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

    【输出样例】

    3
    -1
    3
    

    【提示】

    对于 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。


    LCA的经典应用:静态树上链的权值查询问题
    首先我们考虑找这个无向图的最大生成森林(用Krusal即可),因为根据题意,要求两点之间路径中最小权值的最大值。那么在两点之间,我们必然选择权值尽可能大的边构成这两点间的路径,使得路径中的最小权值尽可能大。
    然后考虑对于每辆货车,如果它的起点和终点不在同一棵树上,说明不能到达目的地,输出-1。否则,我们就可以运用倍增LCA,在求出f数组的同时求dp数组。其中dp[i][j]指从点i出发向上走2^j步 经过的所有路径上的边权最小值。
    (关于倍增LCA:可以看看这个
    状态转移方程:dp[i][0]=w(i,f[i][0])
           dp[i][j]=min(dp[i][j-1],dp[f[i][j-1]][j-1])
    时间复杂度O( mlogm+ nlogn+ qlogn)

      1 #include<bits/stdc++.h>
      2 #define int long long
      3 #define R register int
      4 #define PII pair<int,int>
      5 using namespace std;
      6 const int N=1e6+5,inf=0x3f3f3f3f;
      7 inline int read()
      8 {
      9     char ch=getchar();int num=0;bool flag=false;
     10     while(ch<'0'||ch>'9'){if(ch=='-')flag=true;ch=getchar();}
     11     while(ch>='0'&&ch<='9'){num=num*10+ch-'0';ch=getchar();}
     12     return flag?-num:num;
     13 }
     14 int n,cnt,m,head[N],deep[N],f[N][20],s,fa[N],dp[N][20];
     15 struct Node{
     16     int x,y,z;
     17     bool operator <(const Node &b)const
     18     {
     19         return z>b.z;
     20     }
     21 }ed[N];//存无向图中的边 
     22 struct node{
     23     int to,nxt,w;
     24 }e[N];//存最大生成森林中的边 
     25 int find(int x){return x==fa[x]?fa[x]:fa[x]=find(fa[x]);}
     26 void add(int x,int y,int z)
     27 {
     28     e[++cnt].nxt=head[x];
     29     head[x]=cnt;
     30     e[cnt].to=y;
     31     e[cnt].w=z;
     32 }
     33 void dfs(int x,int fa)
     34 {
     35     deep[x]=deep[fa]+1;
     36     f[x][0]=fa;
     37     for(R i=head[x];i;i=e[i].nxt)
     38     {
     39         int t=e[i].to;
     40         if(t!=fa)
     41         {
     42             dp[t][0]=e[i].w;//dp[i][0]=w(i,f[i][0])
     43             dfs(t,x);
     44         }
     45     }
     46 }
     47 int lca(int x,int y)//直接返回路径中的边权最小值 
     48 {
     49     if(deep[x]<deep[y])swap(x,y);
     50     if(x==y)return 0;
     51     int ans=inf;
     52     for(R j=17;j>=0;j--)
     53         if(deep[f[x][j]]>=deep[y])
     54         {
     55             ans=min(ans,dp[x][j]);
     56             x=f[x][j];
     57         }
     58             
     59     if(x==y)return ans;
     60     for(R j=17;j>=0;j--)
     61         if(f[x][j]!=f[y][j])
     62         {
     63             ans=min(ans,dp[x][j]);
     64             ans=min(ans,dp[y][j]);
     65             x=f[x][j];
     66             y=f[y][j];
     67         }
     68     ans=min(ans,dp[x][0]);ans=min(ans,dp[y][0]);
     69     return ans;
     70 }
     71 signed main()
     72 {
     73     n=read();m=read();
     74     for(R i=1;i<=m;i++)
     75     {
     76         ed[i].x=read(),ed[i].y=read(),ed[i].z=read();
     77     }
     78     sort(ed+1,ed+1+m);
     79     for(R i=1;i<=n;i++)fa[i]=i;
     80     for(R i=1;i<=m;i++)//求最大生成树 
     81     {
     82         int x=find(ed[i].x),y=find(ed[i].y);
     83         if(x!=y)
     84         {
     85             fa[x]=y;
     86             add(ed[i].x,ed[i].y,ed[i].z);
     87             add(ed[i].y,ed[i].x,ed[i].z);
     88         }
     89     }
     90     for(R i=1;i<=n;i++)
     91     {
     92         if(fa[i]==i)//有多个最大生成树 
     93         {
     94             dfs(i,0);
     95             dp[i][0]=inf;
     96         }
     97     }
     98     for(R j=1;j<=17;j++)
     99         for(R i=1;i<=n;i++)
    100         {
    101             f[i][j]=f[f[i][j-1]][j-1];
    102             dp[i][j]=min(dp[f[i][j-1]][j-1],dp[i][j-1]);
    103         }
    104             
    105     int q=read();
    106     while(q--)
    107     {
    108         int x=read(),y=read();
    109         if(find(x)!=find(y))puts("-1");//起点和终点不连通 
    110         else
    111         {
    112             printf("%lld
    ",lca(x,y));
    113         }
    114     }
    115     return 0;
    116 }
    
    
    
     
  • 相关阅读:
    Rsync+sersync 数据同步指南
    rsync 和 inotify 结合
    linux查看 inotify 提供的工具
    linux安装 inotify
    Rsync+inotify 实时数据同步 inotify master 端的配置
    linux手动测试 rsync 的同步情况
    linux安装 rsync 客户端和相关权限认证
    linux为 rsync 添加开机启动
    linux查看 rsync 服务状态
    了解SQL Server锁争用:NOLOCK 和 ROWLOCK 的秘密
  • 原文地址:https://www.cnblogs.com/ljy-endl/p/13572446.html
Copyright © 2011-2022 走看看