题目简介
有多个城市,商人可以在每个城市购买和售卖,询问路线上最多可以赚多少钱,只能进行一次购买和售卖。
思路
多个城市形成一棵树,用四个数组维护,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;
}