题意:给出一个n个节点的树,树上的每个节点都有某个价值的货物,有q次询问,每次询问从u到v的路径上能获得的最大利润(只买一次卖一次)
思路:最开始以为从u到v和从v到u都行,结果样例都过不了……其实可以考虑下uv顺序无关的情况,这种情况下,我们只要知道这条路径中货物价值的最大值和最小值,然后把它们相减就能得到答案了,如果这么对于每个节点我们知道知道三个值就能在用并查集合并的时候解决了:从u到当前根节点的最大值和最小值,从u到当前根节点的最大利润。另外,由于到达v点时,v还没有合并到当前根节点,所以在此时不能直接查询,正确的姿势是把公共祖先anc先求出,然后把这组查询存起来,当访问完anc以后再处理这组查询。那么加上顺序有多大区别呢?其实差不多,只需要多维护一个值罢了:从当前根节点到当前节点的最大利润。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=50000+10;
struct Edge
{
int v,next;
Edge (){};
Edge(int vv,int nx) {v=vv;next=nx;}
}edges[maxn<<1];
struct Node
{
int u,v,id;
Node(){};
Node(int uu,int vv,int ii){u=uu;v=vv;id=ii;}
};
int head[maxn],val[maxn],ans[maxn],nEdge;
int pa[maxn],maxv[maxn],minv[maxn],bestv[maxn],ups[maxn];
bool vis[maxn];
vector<pair<int,int> >querys[maxn];
vector<Node>noq[maxn];
int Find(int x)
{
if(x==pa[x]) return x;
Find(pa[x]);
int y=pa[x];
ups[x]=max(ups[x],max(ups[y],maxv[x]-minv[y]));
bestv[x]=max(bestv[x],max(bestv[y],maxv[y]-minv[x]));
maxv[x]=max(maxv[y],maxv[x]);
minv[x]=min(minv[y],minv[x]);
pa[x]=pa[y];
return pa[x];
}
void AddEdges(int u,int v)
{
edges[++nEdge]=Edge(v,head[u]);
head[u]=nEdge;
edges[++nEdge]=Edge(u,head[v]);
head[v]=nEdge;
}
inline int getbest(int x,int y)
{
int res=max(bestv[x],ups[y]);
res=max(maxv[y]-minv[x],res);
return res;
}
void tarjan(int u,int fa)
{
pa[u]=u;bestv[u]=ups[u]=0;
maxv[u]=minv[u]=val[u];
vis[u]=true;
int v,size,anc;
pair<int,int>pp;
size=querys[u].size();
bool flag;
for(int i=0;i<size;++i)
{
flag=false;
pp=querys[u][i];
v=pp.first;
if(v<0) {v=-v;flag=true;}
if(vis[v])
{
anc=Find(v);
if(flag) noq[anc].push_back(Node(u,v,pp.second));
else noq[anc].push_back(Node(v,u,pp.second));
}
}
for(int k=head[u];k!=-1;k=edges[k].next)
{
v=edges[k].v;
if(v==fa) continue;
tarjan(v,u);
pa[v]=u;
}
size=noq[u].size();
Node node;
for(int i=0;i<size;++i)
{
node=noq[u][i];
Find(node.u);Find(node.v);
ans[node.id]=getbest(node.u,node.v);
}
}
int main()
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
int n,q,u,v;
memset(head,0xff,sizeof(head));
memset(vis,0,sizeof(vis));
nEdge=-1;
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%d",&val[i]);
querys[i].clear();
noq[i].clear();
}
for(int i=1;i<n;++i)
{
scanf("%d%d",&u,&v);
AddEdges(u,v);
}
scanf("%d",&q);
for(int i=0;i<q;++i)
{
scanf("%d%d",&u,&v);
querys[u].push_back(make_pair(-v,i));
querys[v].push_back(make_pair(u,i));
}
tarjan(1,-1);
for(int i=0;i<q;++i)
printf("%d\n",ans[i]);
return 0;
}