给定一个点带权的树,有Q个询问。
一次询问求从X到Y的这条路径上,从一个点买从这个点之后的某个点卖,求最大收益,买必须再卖之前。
求倍增LCA的时候维护5个值
f ij : i的2^j级祖先
fm ij i到i的2^j级祖先的最大点权
fn ij i到i的2^j级祖先的最小点权
sm ij i到i的2^j级祖先的最大收益
sn ij i到i的2^j级祖先的最小收益
从x到y就看成了从x向上到LCA(x,y)向下到y,两条路径分开考虑最后再合并答案即可。
为什么要维护最小收益呢,因为从LCA(x,y)到y的过程就相当于是把从y到LCA(x,y)倒过来看,LCA(x,y)到y的最大值就是y到LCA(x,y)的最小值。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <utility>
#include <map>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
using namespace std;
#define N 50005
int n , m , pre[N] , mcnt , Q;
struct edge
{
int x , next;
}e[N << 1];
int d[N] , f[N][16] , a[N];
int fm[N][16] , fn[N][16] , sm[N][16] , sn[N][16] ;
void dfs(int x , int fa , int dep)
{
d[x] = dep , f[x][0] = fa;
for (int i = pre[x] ; ~i ; i = e[i].next)
if (fa != e[i].x)
dfs(e[i].x , x , dep + 1);
}
int query(int x , int y)
{
int i , xx = 0 , yy = 0 , X = a[x] , Y = a[y];
i = 15;
while (d[x] != d[y])
{
if (abs(d[x] - d[y]) >= 1 << i)
{
if (d[y] < d[x])
xx = max( max(xx , sm[x][i]) , fm[x][i] - X) , X = min(X , fn[x][i]) , x = f[x][i];
else yy = min( min(yy , sn[y][i]) , fn[y][i] - Y) , Y = max(Y , fm[y][i]) , y = f[y][i];
}
-- i;
}
if (x == y)
return max( max(xx , -yy) , Y - X );
i = 15;
while (i >= 0)
{
if (f[x][i] && f[y][i] && f[x][i] != f[y][i])
{
xx = max( max(xx , sm[x][i]) , fm[x][i] - X) , X = min(X , fn[x][i]) , x = f[x][i];
yy = min( min(yy , sn[y][i]) , fn[y][i] - Y) , Y = max(Y , fm[y][i]) , y = f[y][i];
}
-- i;
}
i = 0;
xx = max( max(xx , sm[x][i]) , fm[x][i] - X) , X = min(X , fn[x][i]) , x = f[x][i];
yy = min( min(yy , sn[y][i]) , fn[y][i] - Y) , Y = max(Y , fm[y][i]) , y = f[y][i];
return max( max(xx , -yy) , Y - X );
}
void work()
{
int i , j , x , y;
scanf("%d",&n);
for (i = 1 ; i <= n ; ++ i)
scanf("%d",&a[i]);
memset(pre , -1 , sizeof(pre));
for (i = 1 ; i < n ; ++ i)
{
scanf("%d%d",&x,&y);
e[mcnt] = (edge) {y , pre[x]} , pre[x] = mcnt ++;
e[mcnt] = (edge) {x , pre[y]} , pre[y] = mcnt ++;
}
dfs(1 , 0 , 0);
fm[1][0] = fn[1][0] = a[1] , sm[1][0] = -1 << 30 , sn[1][0] = 1 << 30;
for (i = 2 ; i <= n ; ++ i)
{
fm[i][0] = max(a[i] , a[f[i][0]]);
fn[i][0] = min(a[i] , a[f[i][0]]);
sm[i][0] = max(-a[i] + a[f[i][0]] , 0) , sn[i][0] = min(-a[i] + a[f[i][0]] , 0);
}
for (j = 1 ; 1 << j < n ; ++ j)
for (i = 1 ; i <= n ; ++ i)
{
x = f[i][j - 1];
f[i][j] = f[x][j - 1];
fm[i][j] = max(fm[i][j - 1] , fm[x][j - 1]);
fn[i][j] = min(fn[i][j - 1] , fn[x][j - 1]);
sm[i][j] = max( max(sm[i][j - 1] , sm[x][j - 1]) , fm[x][j - 1] - fn[i][j - 1]);
sn[i][j] = min( min(sn[i][j - 1] , sn[x][j - 1]) , fn[x][j - 1] - fm[i][j - 1]);
}
scanf("%d",&Q);
while (Q --)
{
scanf("%d%d",&x,&y);
printf("%d\n" , query(x , y));
}
}
int main()
{
work();
return 0;
}