一个树有N个节点,每个节点可以买卖同一件物品,不同的节点价格也不相同,给出每个节点的价钱,Q次询问x,y对于每次询问求从x到y最大可以获取的利润。
离线LCA+带权并查集。带权并查集这类的题实在没怎么做过...这题看别人代码都看了好久才看明白...和裸地LCA不同的地方就是这里每个点要维护四个变量,up[x]表示从x到祖先可以获取的最大利润,down[x]表示从祖先到x可以获取的最大利润,mx[x]表示从祖先到x最大的价格,mi[x]表示从祖先到x最小的价格,这四个值在找爸爸的时候更新。记录答案的时候也不太一样,在tarjan的时候,对于查询,先按LCA点把查询归类,在扫面完u的子树后,在去记录u的子树中,x,y的LCA位u的查询的答案,也就是u左侧,u右侧,经过u三种情况找个最大值了。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=50500;
int g1[maxn],g2[maxn],g3[maxn];
int m,p,n,num[maxn];
int mx[maxn],mi[maxn],up[maxn],down[maxn],ans[maxn];
int f[maxn];
bool vis[maxn];
struct EDGE
{
int f,to;
int d,next;
}edge[maxn<<2];
int find(int u)
{
if (u==f[u]) return f[u];
int tmp=f[u];
f[u]=find(f[u]);
up[u]=max(max(up[u],up[tmp]),mx[tmp]-mi[u]);
down[u]=max(max(down[u],down[tmp]),mx[u]-mi[tmp]);
mx[u]=max(mx[u],mx[tmp]);
mi[u]=min(mi[u],mi[tmp]);
return f[u];
}
void tarjan(int u)
{
f[u]=u;
int v,tmp,t;
for (int j=g1[u]; j!=-1; j=edge[j].next)
{
v=edge[j].to;
if (!vis[v])
{
tarjan(v);
f[v]=u;
}
}
vis[u]=true;
for (int j=g2[u]; j!=-1; j=edge[j].next)
{
v=edge[j].to;
if (vis[v])
{
t=find(v);
edge[p].d=j;
edge[p].next=g3[t];
g3[t]=p;
p++;
}
}
int x,y;
for (int j=g3[u]; j!=-1; j=edge[j].next)
{
int kk=edge[j].d;
t=edge[kk].d;
x=edge[kk].f;
y=edge[kk].to;
find(x);
if (t<0)
{
swap(x,y);
t=-t;
}
ans[t]=max(max(up[x],down[y]),mx[y]-mi[x]);
}
}
int main()
{
// freopen("in.txt","r",stdin);
while (~scanf("%d",&n))
{
for (int i=1; i<=n; i++)
{
scanf("%d",&m);
mx[i]=mi[i]=m;
}
memset(vis,false,sizeof vis);
memset(g1,-1,sizeof g1);
memset(g2,-1,sizeof g2);
memset(g3,-1,sizeof g3);
p=0;
int x,y,z;
for (int i=1; i<n; i++)
{
scanf("%d%d",&x,&y);
edge[p].f=x;
edge[p].to=y;
edge[p].next=g1[x];
g1[x]=p;
p++;
// edge[p].f=y;
// edge[p].to=x;
// edge[p].next=g1[y];
// g1[y]=p;
// p++;
}
scanf("%d",&m);
for (int i=1; i<=m; i++)
{
scanf("%d%d",&x,&y);
edge[p].d=i;
edge[p].f=x;
edge[p].to=y;
edge[p].next=g2[x];
g2[x]=p;
p++;
edge[p].d=-i;
edge[p].f=y;
edge[p].to=x;
edge[p].next=g2[y];
g2[y]=p;
p++;
}
tarjan(1);
for (int i=1; i<=m; i++)
cout<<ans[i]<<endl;
}
return 0;
}