洛谷 P1967 货车运输 题解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1967 货车运输 题解相关的知识,希望对你有一定的参考价值。

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

题目链接:https://www.luogu.org/problem/show?pid=1967

题目描述

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

输入输出格式

输入格式:

输入文件名为 truck.in。

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

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

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

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

输出格式:

输出文件名为 truck.out。

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货

车不能到达目的地,输出-1。

输入输出样例

输入样例#1: 
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
输出样例#1: 
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。

 

分析:

(读题10min,写题15min,Debug两小时系列)

要令货车载重最大,需要求最大生成树,货车的路径一定在最大生成树上。

然后在最大生成树上求出货车路径上的最小载重量,即为答案。

求出最大生成树之后暴力求最小载重量应该能拿到60分,具体我并不清楚,一直在试图写正解qwq

(考场上如果遇到了,时间不足1h的话就优先60分吧,我做这道题的时间几乎就一场NOIP了...)

满分做法:最近公共祖先求出从x到y路径上的最小权值。F[i][j]表示从i向上走2^j步到达的节点,

G[i][j]表示从i向上走2^j步过程中的最小权值。整个过程就是多维护了一个G数组,以及lca函数中

返回的答案是ans,其他与最近公共祖先无异。

 

AC代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 const int MAXN = 10002;
  7 const int MAXM = 50002;
  8 inline void Read(int &x)
  9 {
 10     char ch = getchar(),c = ch;x = 0;
 11     while(ch < 0 || ch > 9) c = ch,ch = getchar();
 12     while(ch >= 0 && ch <= 9) x = (x<<1)+(x<<3)+ch-0,ch = getchar();
 13     if(c == -) x = -x;
 14 }
 15 
 16 inline int Min(int a,int b)
 17 {return a<b?a:b;}
 18 
 19 inline int Max(int a,int b)
 20 {return a>b?a:b;}
 21 
 22 inline int Abs(int a)
 23 {return a>=0?a:-a;}
 24 
 25 inline void Swap(int &a,int &b)
 26 {int t = a;a = b,b = t;}
 27 
 28 int n,m,f,t,v,x,y,q,tot;
 29 int Head[MAXM<<1],Fa[MAXN],Fun[MAXN][16],G[100002][16],Deep[MAXN];
 30 
 31 struct Edge
 32 {
 33     int f,t,v,nxt;
 34 }e[MAXM<<1],New[MAXN<<1];
 35 
 36 int cmp(Edge a,Edge b)
 37 {return a.v > b.v;}
 38 
 39 void Newbuild_gw(int f,int t,int v)
 40 {
 41     New[++tot].f = f,New[tot].t = t;
 42     New[tot].v = v,New[tot].nxt = Head[f];
 43     Head[f] = tot;
 44 }
 45 
 46 int find_gw(int x)
 47 {return Fa[x]==x?x:Fa[x]=find_gw(Fa[x]);}
 48 
 49 bool merge_gw(int a,int b)
 50 {
 51     a = find_gw(a),b = find_gw(b);
 52     if(a != b){
 53         Fa[a] = b;
 54         return true;
 55     }
 56     return false;
 57 }
 58 
 59 void dfs_gw(int now)
 60 {
 61     for(int i = Head[now];i;i = New[i].nxt)
 62     {
 63         int tto = New[i].t;
 64         if(Deep[tto]) continue;
 65         Deep[tto] = Deep[now]+1;
 66         Fun[tto][0] = now;
 67         G[tto][0] = New[i].v;
 68         dfs_gw(tto);
 69     }
 70 }
 71 
 72 void Init_gw()
 73 {            
 74     Deep[1] = 0;
 75     dfs_gw(1);
 76     for(int j = 1;j <= 15;++ j)
 77         for(int i = 1;i <= n;++ i)
 78         {
 79             Fun[i][j] = Fun[Fun[i][j-1]][j-1];
 80             G[i][j] = Min(G[i][j-1],G[Fun[i][j-1]][j-1]);
 81         }
 82 }
 83 
 84 int Ask_gw(int x,int y)
 85 {
 86     int Ans = 214748364;
 87     if(Deep[x] > Deep[y]) Swap(x,y);
 88     for(int j = 15;j >= 0;-- j)
 89         if(Deep[y] >= Deep[x]+(1<<j))
 90             Ans = Min(Ans,G[y][j]),y = Fun[y][j];
 91     if(x == y) return Ans;
 92     for(int j = 15;j >= 0;-- j)
 93         if(Fun[x][j] != Fun[y][j])
 94         {
 95             Ans = Min(Ans,Min(G[x][j],G[y][j]));
 96             x = Fun[x][j];
 97             y = Fun[y][j];
 98         }
 99     if(!Fun[x][0]) return -1;
100     Ans = Min(Ans,Min(G[y][0],G[x][0]));
101     return Ans;
102 }
103 
104 int main()
105 {
106 //    freopen("1.txt","r",stdin);
107     Read(n),Read(m);;
108     for(int i = 1;i <= m;++ i)
109         Read(e[i].f),Read(e[i].t),Read(e[i].v);
110     std::sort(e+1,e+1+m,cmp);
111     for(int i=1;i<=n;++i) Fa[i]=i;
112     for(int i = 1;i <= m;++ i)
113         if(merge_gw(e[i].f,e[i].t))
114         {
115             Newbuild_gw(e[i].f,e[i].t,e[i].v);
116             Newbuild_gw(e[i].t,e[i].f,e[i].v);
117         }
118     Init_gw();
119     Read(q);
120     for(int i = 1;i <= q;++ i)
121     {
122         Read(x),Read(y);
123         printf("%d\n",Ask_gw(x,y));
124     }
125     return 0;
126 }

 

以上是关于洛谷 P1967 货车运输 题解的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P1967 货车运输

洛谷P1967货车运输

NOIP 2013 提高组 洛谷P1967 货车运输 (Kruskal重构树)

洛谷 P1967 货车运输生成树+树剖/LCA

货车运输(洛谷P1967)——生成树+倍增LCA的一通乱搞

洛谷P3379lca,HDU2586,洛谷P1967货车运输,倍增lca,树上倍增