(倍增lca)P1967 貨車運輸
阿新 • • 發佈:2018-11-28
https://www.luogu.org/problemnew/show/P1967
A國有n n座城市,編號從 1 到 n,城市之間有 m 條雙向道路。每一條道路對車輛都有重量限制,簡稱限重。現在有 q 輛貨車在運輸貨物, 司機們想知道每輛車在不超過車輛限重的情況下,最多能運多重的貨物。
輸入格式:
第一行有兩個用一個空格隔開的整數 n,m 表示 A 國有 n 座城市和 m 條道路。
接下來 m行每行 3 3個整數 x, y, z,每兩個整數之間用一個空格隔開,表示從 x號城市到 y號城市有一條限重為 z 的道路。注意: x 不等於 y,兩座城市之間可能有多條道路 。
接下來一行有一個整數 q,表示有 q 輛貨車需要運貨。
接下來 q 行,每行兩個整數 x、y,之間用一個空格隔開,表示一輛貨車需要從 x 城市運輸貨物到 y 城市,注意: x 不等於 y 。
輸出格式:
共有 q 行,每行一個整數,表示對於每一輛貨車,它的最大載重是多少。如果貨車不能到達目的地,輸出-1。
為了取得最大流量路徑,每兩個結點之間的路徑是一定的,我們只需要找出這條路徑便可以得到答案,其多餘的路徑是無效的,首先跑出原圖的最大生成樹,用lca處理查詢問題。
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 1e4 + 10; const int maxm = 5e4 + 10; const int INF = 0x3f3f3f3f; int pre[maxn]; int find(int x) { return x == pre[x] ? x : pre[x] = find(pre[x]); } struct Krustral { int u, v, w; bool operator<(const Krustral &a) const { return w > a.w; } } krus[maxm]; vector<pair<int, int>> E[maxn]; int dep[maxn], trefa[maxn][21], wet[maxn][21], vis[maxn]; void dfs(int u) { vis[u] = 1; for (pair<int, int> x : E[u]) { if (vis[x.first]) continue; dep[x.first] = dep[u] + 1; trefa[x.first][0] = u; wet[x.first][0] = x.second; dfs(x.first); } } int lca(int x, int y) { if (find(x) != find(y)) return -1; int ans = INF; if (dep[x] > dep[y]) swap(x, y); register int i; for (i = 20; i >= 0; i--) { if (dep[trefa[y][i]] >= dep[x]) //使x,y同一深度 { ans = min(ans, wet[y][i]); y = trefa[y][i]; } } if (x == y) return ans; for (i = 20; i >= 0; i--) //兩個結點一起向上走 { if (trefa[x][i] != trefa[y][i]) { ans = min(ans, min(wet[x][i], wet[y][i])); x = trefa[x][i]; y = trefa[y][i]; } } ans = min(ans, min(wet[x][0], wet[y][0])); return ans; } int main() { int n, m, q, x, y, z; scanf("%d%d", &n, &m); register int i, j; for (i = 1; i <= n; i++) pre[i] = i; for (i = 0; i < m; i++) { scanf("%d%d%d", &x, &y, &z); krus[i].u = x, krus[i].v = y, krus[i].w = z; } sort(krus, krus + m); int cnt = 0; for (i = 0; i < m; i++) { x = krus[i].u, y = krus[i].v, z = krus[i].w; if (find(x) != find(y)) { E[x].emplace_back(make_pair(y, z)); E[y].emplace_back(make_pair(x, z)); pre[find(x)] = find(y); if (cnt++ == n - 1) break; } } for (i = 1; i <= n; i++) { if (vis[i]) continue; dep[i] = 1; //根節點初始化 dfs(i); trefa[i][0] = i; wet[i][0] = INF; } for (i = 1; i <= 20; i++) //初始化 { for (j = 1; j <= n; j++) { trefa[j][i] = trefa[trefa[j][i - 1]][i - 1]; wet[j][i] = min(wet[j][i - 1], wet[trefa[j][i - 1]][i - 1]); } } scanf("%d", &q); while (q--) { scanf("%d%d", &x, &y); printf("%d\n", lca(x, y)); } // system("pause"); }