传送门
题意:
一个国家有N个城市,每对城市之间只有一条简单的道路。商人选择了一些道路,并希望在每条道路上赚尽可能多的钱。当他沿着一条道路移动时,他可以选择一个城市购买一些商品,然后在一个城市中出售。所有城市的商品都一样,但价格不同。现在,您的任务是计算每条路径上可能的最大利润。
解析:这道题可以用离线LCA+DP解决,也可以用在线LCA+ RMQ。我用的第二种方法,这道题主要是利用grand数组的变形。
maxn[ s ][ i ] 表示 s 到 s向上 2^i 个结点的最大值。
minn[ s ][ i ] 表示 s 到 s向上 2^i 个结点的最小值。
设变量 father =grand [ s ] [ i - 1]
up[ s ][ i ] 表示 s 到 s向上 2^i 个结点的可能存在的答案。
可以由 maxn[ father ][ i - 1] - minn[ s ][ i - 1] , up [ s ] [ i - 1] 和 up [ grand ][ i - 1] 来更新
down[ s ][ i ] 表示 s 到 s向上 2^i 个结点可能存在的答案。
可以由 maxn[ s ][ i - 1] - minn[ father ][ i - 1] , down [ s ] [ i - 1] 和 down [ grand ][ i - 1] 来更新
设 x =LCA( s , e )
我们最后的答案可能存在的三种情况。
① s -> x 这一条链上
② x -> e 这一条链上
③ max(x - >e) - min(s -> x)
注意点:
求解 s -> x 这条链上的答案的时候,需要求解 ( up 数组的最大值 ) 和 ( maxn数组和它后代的最小值的差值的绝对值 ) 的最大值。
同理求解 x - >e 这条链上的答案的时候,需要求解( down数组的最大值 ) 和 (minn数组和它后代最大值的差值的绝对值) 的最大值
记住 N=log2(n) 的值 > 15.....
附上代码:
///#include<bits/stdc++.h>
///#include<unordered_map>
///#include<unordered_set>
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<set>
#include<stack>
#include<map>
#include<new>
#include<vector>
#define MT(a,b) memset(a,b,sizeof(a));
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai=acos(-1.0);
const double E=2.718281828459;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
int n,q;
int value[50005];
struct node
{
int e;
int p;
} load[100005];
int head[50005],sign;
void add_edge(int s,int e)
{
load[++sign]=node{e,head[s]};
head[s]=sign;
}
int depth[50005];
int grand[50005][20],N;
int maxn[50005][20];
int minn[50005][20];
int up[50005][20];
int down[50005][20];
void dfs(int s,int pre)
{
int father;
for(int i=1; i<=N; i++)
{
father=grand[s][i-1];
grand[s][i]=grand[father][i-1];
maxn[s][i]=max(maxn[s][i-1],maxn[father][i-1]);
minn[s][i]=min(minn[s][i-1],minn[father][i-1]);
up[s][i]=max(max(up[s][i-1],up[father][i-1]),maxn[father][i-1]-minn[s][i-1]);
down[s][i]=max(max(down[s][i-1],down[father][i-1]),maxn[s][i-1]-minn[father][i-1]);
}
for(int i=head[s]; i!=-1; i=load[i].p)
{
int e=load[i].e;
if(e!=pre)
{
depth[e]=depth[s]+1;
grand[e][0]=s;
maxn[e][0]=max(value[e],value[s]);
minn[e][0]=min(value[e],value[s]);
up[e][0]=max(0,value[s]-value[e]);
down[e][0]=max(0,value[e]-value[s]);
dfs(e,s);
}
}
}
int get_lca(int a,int b)
{
if(depth[a]>depth[b])
swap(a,b);
for(int i=N; i>=0; i--)
{
if(depth[b]>=depth[a]&&depth[grand[b][i]]>=depth[a])
b=grand[b][i];
}
for(int i=N; i>=0; i--)
{
if(grand[a][i]!=grand[b][i])
{
a=grand[a][i];
b=grand[b][i];
}
}
return a==b?a:grand[b][0];
}
int max_up,max_down;
int MAX,MIN;
void find_up(int s,int e)
{
for(int i=N;i>=0;i--)
{
if(depth[s]>=depth[e]&&depth[grand[s][i]]>=depth[e])
{
max_up=max(max(max_up,up[s][i]),maxn[s][i]-MIN);
MIN=min(MIN,minn[s][i]);
s=grand[s][i];
}
}
}
void find_down(int s,int e)
{
for(int i=N;i>=0;i--)
{
if(depth[s]>=depth[e]&&depth[grand[s][i]]>=depth[e])
{
max_down=max(max(max_down,down[s][i]),MAX-minn[s][i]);
MAX=max(MAX,maxn[s][i]);
s=grand[s][i];
}
}
}
void init()
{
N=log2(n);
sign=0;
memset(head,-1,sizeof(head));
memset(depth,0,sizeof(depth));
memset(grand,0,sizeof(grand));
memset(maxn,0,sizeof(maxn));
memset(minn,0,sizeof(minn));
memset(up,0,sizeof(up));
memset(down,0,sizeof(down));
depth[0]=-1;
}
int main()
{
int s,e;
scanf("%d",&n);
init();
for(int i=1;i<=n;i++)
scanf("%d",&value[i]);
for(int i=1;i<n;i++)
{
scanf("%d %d",&s,&e);
add_edge(s,e);
add_edge(e,s);
}
dfs(1,-1);
scanf("%d",&q);
while(q--)
{
MAX=0;
MIN=INF;
max_up=max_down=0;
scanf("%d %d",&s,&e);
int x=get_lca(s,e);
find_up(s,x);
find_down(e,x);
///cout<<MAX<<" "<<MIN<<" "<<max_up<<" "<<max_down<<endl;
printf("%d\n",max(MAX-MIN,max(max_up,max_down)));
}
return 0;
}