POJ - 3728 The merchant

1 篇文章 0 订阅

POJ - 3728  The merchant VJ地址

题目简介

有多个城市,商人可以在每个城市购买和售卖,询问路线上最多可以赚多少钱,只能进行一次购买和售卖。

思路

多个城市形成一棵树,用四个数组维护,up[maxn][23], down[maxn][23], Max[maxn][23], Min[maxn][23]。

f = fa[ i ][ j-1 ]

  • Max[ i ][ j ] = max(Max[ i ][ j-1 ], Max[ f ][ j-1 ]);           // i ~ i+ 2^j之间的最大值
  • Min[ i ][ j ] = min(Min[ i ][ j-1 ], Min[ f ][ j-1 ]);              //i ~ i+ 2^j之间的最小值
  • up[ i ][ j ] = max(max(up[ i ][ j-1 ], up[ f ][ j-1 ]), Max[ f ][ j-1 ] - Min[ i ][ j-1 ]);             //i ~ i+ 2^j之间的向上走的最小值
  • down[ i ][ j ] = max(max(down[ i ][ j-1 ], down[ f ][ j-1 ]), Max[ i ][ j-1 ] - Min[ f ][ j-1 ]);            //i ~ i+ 2^j之间向下走的最小值​​​​​​​

AC代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn = 1e5+10;
struct Edge{
    int v, next;
}e[maxn*2];
int head[maxn], deep[maxn], fa[maxn][23], cnt, n, m, Max[maxn][23], Min[maxn][23] , a[maxn];
int up[maxn][23], down[maxn][23], num;
void add(int u, int v){
    e[++cnt].v = v;
    e[cnt].next = head[u];
    head[u] = cnt;
}

void dfs(int u, int d){
    deep[u] = d;
    for(int i = head[u]; ~i; i = e[i].next){
        int v = e[i].v;
        if(fa[v][0]) continue;
        fa[v][0] = u;
        Max[v][0] = max(a[v], a[u]);
        Min[v][0] = min(a[v], a[u]);
        up[v][0] = max(a[u] - a[v] , 0);
        down[v][0] = max(a[v] - a[u], 0);
        dfs(v, d+1);
    }
}

void update(){
    for(int j = 1; j <= 20; j++){
        for(int i = 1; i <= n; i++){
            fa[i][j] = fa[fa[i][j-1]][j-1];
            int f = fa[i][j-1];
            Max[i][j] = max(Max[i][j-1], Max[f][j-1]);
            Min[i][j] = min(Min[i][j-1], Min[f][j-1]);
            up[i][j] = max(max(up[i][j-1], up[f][j-1]), Max[f][j-1] - Min[i][j-1]);
            down[i][j] = max(max(down[i][j-1], down[f][j-1]), Max[i][j-1] - Min[f][j-1]);

        }
    }
}

int lca(int u, int v){
    if(deep[u] < deep[v])
        swap(u, v);
    int f = deep[u] - deep[v];
    for(int i = 0; (1<<i) <= f; i++){
        if(f & (1<<i))
            u = fa[u][i];
    }
    if(u != v){
        for(int i = 20; i >= 0; i--){
            if(fa[u][i] != fa[v][i]){
                u = fa[u][i];
                v = fa[v][i];
            }
        }
        u = fa[u][0];
    }
    return u;
}

int solve(int u, int v, int d){   //u:父节点  v :子节点
    int mi = a[v], ma = a[v];
    int f = deep[v] - deep[u];
    for(int i = 0; (1<<i) <= f; i++){
        if(f & (1<<i)){
            if(d == 1){   //向上
                num = max(num, up[v][i]);
                num = max(num, Max[v][i] - mi);
                mi = min(mi, Min[v][i]);
            }
            else{
                num = max(num, down[v][i]);
                num = max(num, ma - Min[v][i]);
                ma = max(ma, Max[v][i]);
            }
            v = fa[v][i];
        }
    }
    if(d == 1){
        return mi;
    }
    return ma;
}





int main(){
    while(scanf("%d", &n) != EOF){
        for(int i = 1; i <= n; i++){
            scanf("%d", &a[i]);
        }
        memset(head, -1, sizeof(head));
        memset(fa, 0, sizeof(fa));
        memset(up, 0, sizeof(up));
        memset(down, 0, sizeof(down));
        memset(Min, 0x3f, sizeof(Min));
        memset(Max, 0, sizeof(Max));
        cnt = 0;
        int u, v;
        for(int i = 1; i < n; i++){
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }
        fa[1][0] = 1;
        Min[1][0] = a[1];
        Max[1][0] = a[1];
        dfs(1, 1);
        update();
        scanf("%d", &m);
        for(int i = 1; i <= m; i++){
            scanf("%d%d", &u, &v);
            int f = lca(u, v);
            num = 0;
            num = max(num,  solve(f, v, 2) - solve(f, u, 1));
            printf("%d\n", num);
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值