此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。
题目链接: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 }