H - Traveling Plan ZOJ - 4001(路径最大值最小,最小生成树)

BaoBao loves traveling very much. There are (N) cities marked on his traveling map, and some of them have food supplies while others have not.

During his journey, he must take enough food so that he won’t starve. There are (M) roads on the map, each connecting two cities. These roads are bi-directional. For each road, we know the exact cost of food. Notice that only when BaoBao arrives in a city which is able to provide food can he refill his food to the maximum capacity.

BaoBao has (Q) journey plans. For each plan, it is guaranteed that both the starting city and the destination city have food supplies. Now BaoBao wants you to help him determine the maximum food capacity of his carriage for each plan. For his convenience, he hopes it can be as small as possible.

Input
There is only one test case.

The first line of the input contains two integers (N) and (M) ((1 \le N \le 10^5), (1 \le M \le 2 \times 10^5)), denoting that there are (N) cities and (M) bi-directional roads.

The second line contains (N) integers (a_1, a_2, \dots, a_N). If (a_i = 1), the (i)-th city has food supplies; If (a_i = 0), the (i)-th city has no food supplies.

The following (M) lines each contains three integers (X), (Y) and (W) ((X \ne Y), (1 \le W \le 10^9)), denoting that there is a road connecting the (X)-th and the (Y)-th city with a food cost of (W). It is guaranteed that there exists at most one road between each pair of (X) and (Y).

The following line contains an integer (Q) ((1 \le Q \le 10^5)), the number of queries.

The following (Q) lines each contains two integers (X) and (Y), denoting the starting city and the destination city for each query. It is guaranteed that both (X) and (Y) are cities with food supplies.

Output
For each query output one line containing one integer, indicating the smallest food capacity.

Sample Input
6 7
1 0 1 0 1 1
1 2 2
1 4 1
2 3 2
4 5 4
3 6 10
3 5 2
5 6 5
2
1 6
1 5
Sample Output
5
4

题意:
一个无向图,有一些点能充满能量(变成初始能量值),行走过程中能量不能减少为负数。每次询问给出两个点,求A点到达B点所能剩下的最少能量(要求你确定初始能量)。
保证询问的点都是能充能量的点

思路:
看了题解才想起来,MST还能维护两点之间路径最大(小)边的啊,因为最小生成树每次维护的连接是两个连通分量的最短边。(图论忘光了。

定义 d [ x ] d[x] d[x]为x到最近充电桩的距离,然后将边(x,y,w)替换成(x,y,w+d[x]+d[y]),代表这条边的最小耗费。此时问题就变成了求两点路径最小边,所以用最小生成树维护。

因为假设初始能量为V,那么到达起点终点的能量都是V,所以实质上就是要我们最小化V。则这个点到达了任意一个点后,我们要再通过一些操作使得这个点当前能量尽可能大,这样需要的初始能量V才尽可能小。

所以对于边 x->y,边权w。我们先从x走到一个最近充电桩再返回,此时到了x点能量才最大, V V V至少为 d [ x ] d[x] d[x]。经过了这条边到达B点,V至少为 d [ x ] + w d[x]+w d[x]+w。此时到达了B点,但是之后还是要从B点出发,所以得最大化B点的能量又不能保证能量为负数,所以此时V至少为 d [ x ] + d [ y ] + w d[x]+d[y]+w d[x]+d[y]+w,这就是这条边对于初始能量V的限制。

求出两点路径限制的最大值,就是最小初始能量了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

typedef long long ll;
const int maxn = 4e5 + 7;

int head[maxn],nex[maxn],to[maxn],tot;
ll val[maxn];
int vis[maxn];
ll d[maxn];
int a[maxn];
priority_queue<pair<ll,int>>q;

void add(int x,int y,ll z) {
    
    
    to[++tot] = y;
    nex[tot] = head[x];
    val[tot] = z;
    head[x] = tot;
}

void dijkstra() {
    
    
    while(!q.empty()) {
    
    
        int now = q.top().second;q.pop();
        if(vis[now]) continue;
        vis[now] = 1;
        for(int i = head[now];i;i = nex[i]) {
    
    
            int v = to[i];
            ll w = val[i];
            if(d[v] > d[now] + w) {
    
    
                d[v] = d[now] + w;
                q.push({
    
    -d[v],v});
            }
        }
    }
}

struct Edge {
    
    
    int x,y;
    ll w;
}edges[maxn];

int cmp(Edge a,Edge b) {
    
    
    return a.w < b.w;
}

int fa[maxn][20];
ll fw[maxn][20];
int f[maxn];

void dfs(int x) {
    
    
    for(int i = head[x];i;i = nex[i]) {
    
    
        int v = to[i];
        ll w = val[i];
        if(!d[v]) {
    
    
            d[v] = d[x] + 1;
            fa[v][0] = x;
            fw[v][0] = w;
            dfs(v);
        }
    }
}

int findset(int x) {
    
    
    if(f[x] == x) return x;
    return f[x] = findset(f[x]);
}

ll lca(int x,int y) {
    
    
    ll ans = 0;
    if(d[x] < d[y]) {
    
     //保证x是最深的
        swap(x,y);
    }
    
    for(int i = 19;i >= 0;i--) {
    
     //x跳到和y一样高
        if(d[fa[x][i]] >= d[y]) {
    
    
            ans = max(ans,fw[x][i]);
            x = fa[x][i];
        }
    }

    if(x == y) {
    
    
        return ans;
    }
    for(int i = 19;i >= 0;i--) {
    
     //两个小朋友一起跳
        if(fa[x][i] != fa[y][i]) {
    
    
            ans = max(fw[x][i],ans);
            ans = max(fw[y][i],ans);
            x = fa[x][i];
            y = fa[y][i];
        }
    }
    ans = max(ans,max(fw[x][0],fw[y][0]));
    return ans;
}

int main() {
    
    
    int n,m;scanf("%d%d",&n,&m);
    memset(d,0x3f,sizeof(d));
    for(int i = 1;i <= n;i++) {
    
    
        scanf("%d",&a[i]);
        if(a[i]) {
    
    
            q.push({
    
    0,i});
            d[i] = 0;
        }
    }
    for(int i = 1;i <= m;i++) {
    
    
        int x,y,w;scanf("%d%d%d",&x,&y,&w);
        edges[i] = {
    
    x,y,w};
        add(x,y,w);
        add(y,x,w);
    }
    
    dijkstra();
    for(int i = 1;i <= m;i++) {
    
    
        edges[i].w += d[edges[i].x] + d[edges[i].y];
    }
    sort(edges + 1,edges + 1 + m,cmp);

    tot = 0;
    memset(d,0,sizeof(d));
    memset(head,0,sizeof(head));
    
    for(int i = 1;i <= n;i++) f[i] = i;
    for(int i = 1;i <= m;i++) {
    
    
        int x = edges[i].x,y = edges[i].y;
        ll w = edges[i].w;
        int rx = findset(x),ry = findset(y);
        if(rx != ry) {
    
    
            f[rx] = ry;
            add(x,y,w);
            add(y,x,w);
        }
    }
    
    fa[1][0] = 0;
    d[1] = 1;
    dfs(1);
    for(int i = 1;i <= n;i++) {
    
    
        if(!d[i]) dfs(i);
    }
    
    for(int i = 1;i <= 19;i++) {
    
    
        for(int j = 1;j <= n;j++) {
    
    
            fa[j][i] = fa[fa[j][i - 1]][i - 1];
            fw[j][i] = max(fw[fa[j][i - 1]][i - 1],fw[j][i - 1]);
        }
    }
    
    int T;scanf("%d",&T);
    while(T--) {
    
    
        int x,y;scanf("%d%d",&x,&y);
        printf("%lld\n",lca(x,y));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/109072969
今日推荐