P1967 [NOIP2013 提高组] 货车运输(最大生成树+倍增lca)
A 国有 n 座城市,编号从 1到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。
思路:两点间能运送的最重货物就是某相连路线上的最小限制重量,于是我们对原图找最大生成树,
这样得到的两点唯一路径上就是能运送最大重量的路径,然后求路径上的最小限重就用求出来的
生成树上倍增求解就行.
code:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 100005; const int inf = 0x3f3f3f3f; const ll mod = 100000000; struct edge { int f, t, nxt; ll dis; }e[maxn]; int hd[maxn], tot; void add(int f, int t, ll dis) { e[++tot] = { f,t,hd[f],dis }; hd[f] = tot; } struct node { int u, v, w; bool operator<(node b)const { return w > b.w; } }a[maxn]; int n, m; int fa[maxn]; int find(int x) { return x == fa[x] ? x : fa[x] = find(fa[x]); } int f[maxn][30],mi[maxn][30],dep[maxn]; void dfs(int u,int ff) { for (int i = 1; i <=20; i++) {//树上倍增 f[u][i] = f[f[u][i - 1]][i - 1]; if (!f[u][i])break; mi[u][i] = min(mi[f[u][i - 1]][i - 1], mi[u][i - 1]); } for (int i = hd[u]; i; i = e[i].nxt) { int v = e[i].t, w = e[i].dis; if (v == ff)continue; f[v][0] = u; mi[v][0] = w; dep[v] = dep[u] + 1; dfs(v,u); } } int qurry(int x, int y) {//x-y路径上的最小值,倍增查询模板 if (find(x) != find(y))return -1; if (dep[x] < dep[y])swap(x, y); //cout << dep[x] << " " << dep[y] << endl; int ans = inf; for (int i = 20; i >= 0; i--) { if (dep[f[x][i]] >= dep[y]) { //cout << i << " " << x <<" "<<f[x][i]<<" "<<mi[x][i]<< endl; ans = min(ans, mi[x][i]); x = f[x][i]; } } //cout << ans << endl; if (x == y)return ans; for (int i = 20; i >= 0; i--) { if (f[x][i] != f[y][i]) { ans = min(ans, min(mi[x][i], mi[y][i])); x = f[x][i]; y = f[y][i]; } } return min(ans, min(mi[x][0], mi[y][0])); } int main() { //freopen("test.txt", "r", stdin); scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { fa[i] = i; } for (int i = 1; i <= m; i++) { scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].w); } sort(a + 1, a + m + 1); for (int i = 1; i <= m; i++) {//kruskal int u = a[i].u, v = a[i].v, w = a[i].w; if (find(u) != find(v)) { add(u, v, w);//建生成树 add(v, u, w); fa[find(u)] = find(v); } } memset(mi, 0x3f, sizeof(mi));//初始化最大 for (int i = 1; i <= n; i++) { if (find(i) == i) { dep[i] = 1; dfs(i,0); } } int q; scanf("%d", &q); while (q--) { int a, b; scanf("%d%d", &a, &b); printf("%d\n", qurry(a, b)); } return 0; }