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;
}

 

posted @ 2021-05-26 21:05  cono奇犽哒  阅读(65)  评论(0编辑  收藏  举报