一个树有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; }