【noip2013】货车运输 (最大生成树 + 倍增)
题目描述 Description
A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
输入描述 Input Description
第一行有两个用一个空格隔开的整数 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 Description
输出共有 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
数据范围及提示 Data Size & 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。
题目分析
首先若两地不联通直接输出-1(并查集判断)。要想限重大,那么一定是在最大生成树上走,剩下的工作就是找出再生成树上x-y的路径上的最小权值,直接枚举边肯定会TLE,考虑使用倍增算法:fa[u][i]表示u向上跳2i后的点是谁,这样fa[u][0]就是父节点。minn[u][i]表示u到fa[u][i]这条路径上的最小权值。dfs时就可以预处理出来,接着就可以像求lca一样求出去最小权值。
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<vector> using namespace std; const int N = 1e4 + 5, M = 5e4 + 5, oo = 0x3f3f3f3f; int n, m, ecnt, Q; struct Edge{ int u, v, w; }edge[M << 1]; int adj[N], go[M << 1], nxt[M << 1], len[M << 1]; int anc[N], Log[N]; int fa[N][30], minn[N][30], dep[N]; bool vst[N]; inline bool cmp( const Edge &a, const Edge &b){ return a.w>b.w; } inline void addEdge( int u, int v, int w){ nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, len[ecnt] = w; nxt[++ecnt] = adj[v], adj[v] = ecnt, go[ecnt] = u, len[ecnt] = w; } inline void dfs( int u){ for ( int i = 1; fa[u][i - 1]; i++){ fa[u][i] = fa[fa[u][i - 1]][i - 1]; minn[u][i] = min(minn[u][i - 1], minn[fa[u][i - 1]][i - 1]); } for ( int e = adj[u], v; e; e = nxt[e]){ if ((v = go[e]) == fa[u][0]) continue ; fa[v][0] = u; dep[v] = dep[u] + 1; minn[v][0] = len[e]; dfs(v); vst[v] = true ; } } inline int query( int u, int v){ if (dep[u] < dep[v]) swap(u, v); int delta = dep[u] - dep[v], ret = oo; for ( int i = Log[delta]; i >= 0; i--) if ((1 << i) & delta){ ret = min(ret, minn[u][i]); u = fa[u][i]; } if (u == v) return ret; for ( int i = Log[dep[u]]; i >= 0; i--) if (fa[u][i] != fa[v][i]){ ret = min(ret, min(minn[u][i], minn[v][i])); u = fa[u][i], v = fa[v][i]; } ret = min(ret, min(minn[u][0], minn[v][0])); return ret; } inline void initLog(){ Log[0] = -1; for ( int i = 1; i <= n; i++) Log[i] = Log[i >> 1] + 1; } inline int getAnc( int u){ return anc[u] == u ? u : (anc[u] = getAnc(anc[u])); } inline int read(){ int i = 0, f = 1; char ch = getchar (); for (; (ch < '0' || ch > '9' ) && ch != '-' ; ch = getchar ()); if (ch == '-' ) f = -1, ch = getchar (); for (; ch >= '0' && ch <= '9' ; ch = getchar ()) i = (i << 3) + (i << 1) + (ch - '0' ); return i * f; } inline void wr( int x){ if (x < 0) putchar ( '-' ), x = -x; if (x > 9) wr(x / 10); putchar (x % 10 + '0' ); } int main(){ n = read(), m = read(); initLog(); for ( int i = 1; i <= n; i++) anc[i] = i; for ( int i = 1; i <= m; i++){ int x = read(), y = read(), z = read(); edge[i].u = x, edge[i].v = y, edge[i].w = z; } sort(edge + 1, edge + m + 1, cmp); for ( int i = 1; i <= m; i++){ Edge e = edge[i]; int f = getAnc(e.u), g = getAnc(e.v); if (f != g){ anc[f] = g; addEdge(e.u, e.v, e.w); } } for ( int i = 1; i <= n; i++) if (!vst[i]){ vst[i] = true ; dfs(i); } Q = read(); while (Q--){ int x = read(), y = read(); int f = getAnc(x), g = getAnc(y); if (f != g) wr(-1), putchar ( '\n' ); else wr(query(x, y)), putchar ( '\n' ); } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步