欢迎来到endl的博客hhh☀☾☽♡♥

浏览器标题切换
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【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\n",lca(x,y));
113         }
114     }
115     return 0;
116 }

 

 
posted @ 2020-08-27 17:00  endl\n  阅读(341)  评论(0编辑  收藏  举报