[NOIP2013 提高組] 貨車運輸
阿新 • • 發佈:2020-12-30
前言
使用演算法:堆優化 \(prim\) , \(LCA\) 。
題意
共有 \(n\) 個點,有 \(m\) 條邊來連線這些點,每條邊有權值。有 \(q\) 條類似於 \(u\) \(v\) 詢問,求一條從 \(u\) 到 \(v\) 的路徑使得路徑上的最小權值最大,求這個最大值。若不存在從 \(u\) 到 \(v\) 的路徑,則輸出 \(-1\) 。
思路
先求該圖的最大生成樹,因為需要使得該路徑上的最小值最大,而這條路徑就是最小生成樹的中兩點的簡單路徑(最大生成樹儘量取最大的邊)。
故而,查詢時的路徑確定了,那麼現在就是求這條路徑的最小值了。
樹上的距離操作離不開 \(LCA\) 。
假設查詢 \(2\)
查詢兩個點是否在路徑很簡單,就是判斷他們是否在一個連通塊,直接在處理 \(prim\) 時一起求解即可。
C++程式碼
#include <queue> #include <cstdio> #include <vector> #include <cstring> using namespace std; #define INF 0x3f3f3f3f #define Swap(a, b) (a ^= b ^= a ^= b) #define Min(a, b) ((a) < (b) ? (a) : (b)) void Quick_Read(int &N) { N = 0; int op = 1; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') op = -1; c = getchar(); } while(c >= '0' && c <= '9') { N = (N << 1) + (N << 3) + (c ^ 48); c = getchar(); } N *= op; } const int MAXN = 1e4 + 5; const int MAXM = 40; struct Node { int to, dist; Node() {} Node(int T, int D) { to = T; dist = D; } friend bool operator < (Node x, Node y) { return x.dist < y.dist; } }; int fa[MAXN][MAXM], minn[MAXN][MAXM]; int de[MAXN]; vector<Node> v[MAXN]; priority_queue<Node> q; bool vis[MAXN]; int dis[MAXN], belong[MAXN]; int ans, tot; int n, m, t; int LCA(int x, int y) { if(de[x] < de[y]) Swap(x, y); for(int i = 30; i >= 0; i--) if(de[x] - (1 << i) >= de[y]) x = fa[x][i]; if(x == y) return x; for(int i = 30; i >= 0; i--) { if(fa[x][i] != fa[y][i]) { x = fa[x][i]; y = fa[y][i]; } } return fa[x][0]; } int Climb(int x, int y) { int res = INF; for(int i = 30; i >= 0; i--) if(de[x] - (1 << i) >= de[y]) { res = Min(res, minn[x][i]); x = fa[x][i]; } return res; } void Prim(int s) { tot++; dis[s] = 0; q.push(Node(s, 0)); fa[s][0] = s; while(!q.empty()) { int now = q.top().to, adddist = q.top().dist; q.pop(); if(vis[now]) continue; belong[now] = tot; ans += adddist; vis[now] = true; int SIZ = v[now].size(); for(int i = 0; i < SIZ; i++) { int next = v[now][i].to; if(v[now][i].dist > dis[next] && !vis[next]) { fa[next][0] = now; de[next] = de[now] + 1; minn[next][0] = v[now][i].dist; dis[next] = v[now][i].dist; q.push(Node(next, dis[next])); } } } } void Query() { int A, B; Quick_Read(t); for(int i = 1; i <= t; i++) { Quick_Read(A); Quick_Read(B); if(belong[A] != belong[B]) printf("-1\n"); else { int lca = LCA(A, B); int ans1 = Climb(A, lca); int ans2 = Climb(B, lca); printf("%d\n", Min(ans1, ans2)); } } } void Build() { memset(dis, 128, sizeof(dis)); for(int i = 1; i <= n; i++) if(!vis[i]) Prim(i); for(int j = 1; j < 31; j++) for(int i = 1; i <= n; i++) { fa[i][j] = fa[fa[i][j - 1]][j - 1]; minn[i][j] = Min(minn[fa[i][j - 1]][j - 1], minn[i][j - 1]); } } void Read() { int A, B, C; Quick_Read(n); Quick_Read(m); for(int i = 1; i <= m; i++) { Quick_Read(A); Quick_Read(B); Quick_Read(C); v[A].push_back(Node(B, C)); v[B].push_back(Node(A, C)); } } int main() { Read(); Build(); Query(); return 0; }