题意:
给出N个点,和每个点物品的售价,现在有一个商人,要从u点到v点,他想在路上多赚点钱。他可以从一个城市买物品,然后再卖到另一个城市,但买卖只允许一次,且不能回头走 问最多能赚多少
题解:
对于一个询问, 假设u,v的LCA是f
有三种可能, 一个是从u到f 买卖了。 一个是从f到v买卖了, 一个是从u到f之间买了,从v到f卖了
在原有倍增数组的基础上,新开四个数组,分别表示:
dp_max:向上走2^k步之间的最高价格
dp_min:向上走2^k步之间的最低价格
dp_up:从u向上走2^k步的最大利润
dp_down:向下走2^k步到u的最大利润
然后对于每次询问,比较三个值:
从u到f买卖的最大利润
从f到v买卖的最大利润
从u到f买,从v到f卖的最大利润
俺又自闭了,智商跟不上...
#include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn=1e5; int N; int head[maxn]; int tol; struct node { int u; int v; int next; }edge[maxn]; void addedge (int u,int v) { edge[tol].u=u; edge[tol].v=v; edge[tol].next=head[u]; head[u]=tol++; } int weight[maxn]; int h[maxn]; int father[20][maxn]; int dp_max[20][maxn];//向上走2^k步之间的最高价格 int dp_min[20][maxn];//向上走2^k步之间的最低价格 int dp_up[20][maxn];//从u向上走2^k的最大利润 int dp_down[20][maxn];//向下走2^k步到u的最大利润 void dfs (int x) { for (int i=head[x];i!=-1;i=edge[i].next) { int v=edge[i].v; if (v==father[0][x]) continue; father[0][v]=x; h[v]=h[x]+1; dp_up[0][v]=max(weight[x]-weight[v],0); dp_down[0][v]=max(weight[v]-weight[x],0); dp_max[0][v]=max(weight[v],weight[x]); dp_min[0][v]=min(weight[v],weight[x]); dfs(v); } } int lca (int x,int y) { if (h[x]<h[y]) swap(x,y); for (int i=17;i>=0;i--) if (h[x]-h[y]>>i) x=father[i][x]; if (x==y) return x; for (int i=17;i>=0;i--) if (father[i][x]!=father[i][y]) { x=father[i][x]; y=father[i][y]; } return father[0][x]; } int up (int u,int k,int &Min) { Min=1e9; int ans=0,preMin=1e9; for (int i=16;i>=0;i--) { if (k>>i&1) { Min=min(Min,dp_min[i][u]); ans=max(ans,dp_up[i][u]); ans=max(ans,dp_max[i][u]-preMin); preMin=min(preMin,dp_min[i][u]); u=father[i][u]; } } return ans; } int down (int u,int k,int &Max) { Max=0; int ans=0,preMax=0; for (int i=16;i>=0;i--) { if (k>>i&1) { Max=max(Max,dp_max[i][u]); ans=max(ans,dp_down[i][u]); ans=max(ans,preMax-dp_min[i][u]); preMax=max(preMax,dp_max[i][u]); u=father[i][u]; } } return ans; } int main () { scanf("%d",&N); for (int i=1;i<=N;i++) scanf("%d",&weight[i]); memset(head,-1,sizeof(head)); memset(dp_max,0,sizeof(dp_max)); memset(dp_min,0x3f,sizeof(dp_min)); tol=0; for (int i=0;i<N-1;i++) { int u,v; scanf("%d%d",&u,&v); addedge(u,v); addedge(v,u); } int q; dfs(1); for (int i=1;i<=17;i++) for (int j=1;j<=N;j++) { father[i][j]=father[i-1][father[i-1][j]]; int mid=father[i-1][j]; dp_max[i][j]=max(dp_max[i-1][j],dp_max[i-1][mid]); dp_min[i][j]=min(dp_min[i-1][j],dp_min[i-1][mid]); dp_up[i][j]=max(max(dp_up[i-1][j],dp_up[i-1][mid]),dp_max[i-1][mid]-dp_min[i-1][j]); dp_down[i][j]=max(max(dp_down[i-1][j],dp_down[i-1][mid]),dp_max[i-1][j]-dp_min[i-1][mid]); } scanf("%d",&q); for (int i=1;i<=q;i++) { int x,y; scanf("%d%d",&x,&y); int Min=1e9,Max=-1; int r=lca(x,y); int up_w=up(x,h[x]-h[r],Min); int down_w=down(y,h[y]-h[r],Max); printf("%d ",max(max(up_w,down_w),Max-Min)); } }