NOIp 2013 Day1T3 货车运输
Description
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
Input:
输入文件名为 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 。
Output
输出文件名为 truck.out。
输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货
车不能到达目的地,输出-1。
Sample Input:
4 3
1 2 4
2 3 3
3 1 1
3
1 3
1 4
1 3
Sample Output:
3
-1
3
HINT
对于 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。
方法一: 最大生成树 + 树上倍增,代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 const int maxn = 10000 + 5; 8 const int maxm = 100000 + 5; 9 struct Edge 10 { 11 int f, t, v; 12 bool operator < (const Edge a) const 13 { 14 return v > a.v; 15 } 16 }gra[maxm], edg[maxm]; 17 int n, m, q, u; 18 int fir[maxn], nxt[maxn << 1], fa[maxn]; 19 int dep[maxn], p[maxn][21], minn[maxn][21]; 20 bool used[maxn]; 21 void Build(int, int, int), Kruskal_hu(), DFS(int), Pre_lca(); 22 int Ask_lca(int, int), Ask_ans(int, int, int), Find(int); 23 24 int main() 25 { 26 memset(fir, -1, sizeof(fir)); 27 memset(minn, 0x7f, sizeof(minn)); 28 scanf("%d%d", &n, &m); 29 for(int i = 0; i < m; i++) 30 { 31 int f, t, v; 32 scanf("%d%d%d", &f, &t, &v); 33 edg[i] = (Edge){f, t, v}; 34 } 35 Kruskal_hu(); 36 DFS(1); 37 Pre_lca(); 38 scanf("%d", &q); 39 while(q--) 40 { 41 int x, y; 42 scanf("%d%d", &x, &y); 43 if(Find(x) != Find(y)) puts("-1"); 44 else 45 { 46 int lca = Ask_lca(x, y); 47 printf("%d\n", Ask_ans(x, lca, y)); 48 } 49 } 50 return 0; 51 } 52 53 int Ask_ans(int x, int pa, int y) 54 { 55 int ans = 1e9 + 7; 56 int f = dep[x] - dep[pa]; 57 for(int i = 20; i >= 0; i--) 58 if((1 << i)&f) 59 { 60 ans = min(ans, minn[x][i]); 61 x = p[x][i]; 62 } 63 f = dep[y] - dep[pa]; 64 for(int i = 20; i >= 0; i--) 65 if((1 << i)&f) 66 { 67 ans = min(ans, minn[y][i]); 68 y = p[y][i]; 69 } 70 return ans; 71 } 72 73 void Pre_lca() 74 { 75 for(int j = 1; (1 << j) <= n; j++) 76 for(int i = 1; i <= n; i++) 77 { 78 p[i][j] = p[p[i][j - 1]][j - 1]; 79 minn[i][j] = min(minn[i][j - 1], minn[p[i][j - 1]][j - 1]); 80 } 81 } 82 83 void DFS(int k) 84 { 85 used[k] = 1; 86 for(int i = fir[k]; ~i; i = nxt[i]) 87 { 88 int tmp = gra[i].t; 89 if(used[tmp]) continue; 90 p[tmp][0] = k; 91 dep[tmp] = dep[k] + 1; 92 minn[tmp][0] = gra[i].v; 93 DFS(tmp); 94 } 95 } 96 97 int Ask_lca(int x, int y) 98 { 99 if(dep[x] > dep[y]) swap(x, y); 100 int f = dep[y] - dep[x]; 101 for(int i = 0; (1 << i) <= f; i++) 102 if((1 << i)&f) y = p[y][i]; 103 if(x != y) 104 { 105 for(int i = 20; i >= 0; i--) 106 if(p[x][i] != p[y][i]) 107 { 108 x = p[x][i]; 109 y = p[y][i]; 110 } 111 x = p[x][0]; 112 } 113 return x; 114 } 115 116 void Build(int f, int t, int v) 117 { 118 gra[++u] = (Edge){f, t, v}; 119 nxt[u] = fir[f], fir[f] = u; 120 gra[++u] = (Edge){t, f, v}; 121 nxt[u] = fir[t], fir[t] = u; 122 } 123 124 int Find(int x) 125 { 126 return fa[x] == x ? x : fa[x] = Find(fa[x]); 127 } 128 129 void Kruskal_hu() 130 { 131 for(int i = 1; i <= n; i++) fa[i] = i; 132 sort(edg, edg + m); 133 for(int i = 0; i < m; i++) 134 { 135 int x = Find(edg[i].f), y = Find(edg[i].t); 136 if(x != y) 137 { 138 Build(edg[i].f, edg[i].t, edg[i].v); 139 fa[x] = y; 140 } 141 } 142 }
方法二:树链剖分 + 线段树,各种错误,弃坑