poj3728


u->v最优解=极大卖出-极小买入,记最近公共祖先r,穷举三种情况:
u->v最优解=u->r最优解
u->v最优解=r->v最优解
u->v最优解=r->v极大卖出-u->r极小买入
 
</pre><pre name="code" class="cpp">#include<iostream>
#include <string> 
#include<vector>
#include<algorithm>
#include<set>
#include<cmath>
using namespace std;
#define lch(i) ((i)<<1)
#define rch(i) ((i)<<1|1)
#define sqr(i) ((i)*(i))
#define pii pair<int,int>
#define mp make_pair
#define FOR(i,b,e) for(int i=b;i<=e;i++)
#define ms(a)	memset(a,0,sizeof(a))
const int maxnum = 50005;

struct node
{
	int v,next;
}edge[maxnum*2];
struct node1
{
	int v,nth,next,dir;
}qedge[maxnum*2];
int p[maxnum],max1[maxnum],min1[maxnum],r2rt[maxnum],rt2r[maxnum],pre[maxnum];
int head[maxnum],query[maxnum],vis[maxnum];
int ans[maxnum];

int ca[maxnum];
int find1(int i){
	if(p[i]==i){
		return p[i];
	}
	int tmp = p[i];
	p[i]=find1(p[i]);
	r2rt[i]=max(max(r2rt[i],r2rt[tmp]),max1[i]-min1[tmp]);
	rt2r[i]=max(max(rt2r[i],rt2r[tmp]),max1[tmp]-min1[i]);
	max1[i]=max(max1[tmp],max1[i]);
	min1[i]=min(min1[tmp],min1[i]);
	return p[i];
}

void uniontree(int rx,int ry){
	p[ry]=rx;
}

void dfs(int rt){
	p[rt]=rt;
	for(int i=head[rt];i!=-1;i=edge[i].next){
		if(edge[i].v==pre[rt])continue;
		pre[edge[i].v]=rt;
		dfs(edge[i].v);
		uniontree(rt,find1(edge[i].v));
	}
	vis[rt]=1;
	for(int i=query[rt];i!=-1;i=qedge[i].next){
		if(!vis[qedge[i].v])continue;
		int ca = find1(qedge[i].v);
		if(qedge[i].dir==0){
			int rtr=0,mi=min1[rt],pi=rt;
			while(pi!=ca){
				rtr=max(max(rtr,max1[pre[pi]]-max1[pi]),max1[pre[pi]]-mi);
				mi = min(mi,min1[pre[pi]]);
				pi=pre[pi];
			}
			ans[qedge[i].nth]=max(max(rtr,r2rt[qedge[i].v]),max1[qedge[i].v]-mi);
		}
		else{
			int rrt=0,ma=max1[rt],pi=rt;
			while(pi!=ca){
				rrt=max(max(rrt,max1[pi]-max1[pre[pi]]),ma-min1[pre[pi]]);
				ma = max(ma,max1[pre[pi]]);
				pi=pre[pi];
			}
			ans[qedge[i].nth]=max(max(rrt,rt2r[qedge[i].v]),ma-min1[qedge[i].v]);
		}

	}
	
}

int e=0;
void add(int u,int v){
	edge[e].v=v;
	edge[e].next=head[u];
	head[u]=e++;
}

int f=0;
void addq(int u,int v,int i,int dir){
	qedge[f].v=v;
	qedge[f].next=query[u];
	qedge[f].nth=i;
	qedge[f].dir=dir;
	query[u]=f++;
}
int main()
{
	int n,q,u,v;
	scanf("%d",&n);
	FOR(i,1,n){
		scanf("%d",&max1[i]);
		min1[i]=max1[i];
		r2rt[i]=rt2r[i]=0;
		head[i]=-1;
		query[i]=-1;
		vis[i]=0;
	}
	FOR(i,1,n-1){
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);	
	}
	scanf("%d",&q);
	FOR(i,1,q){
		scanf("%d%d",&u,&v);
		addq(u,v,i,0);
		addq(v,u,i,1);
	}
	ms(p);
	pre[1]=0;
	dfs(1);
	FOR(i,1,q){
		printf("%d\n",ans[i]);
	}
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值