There are N cities in a country, and there is one and only one simple path between each pair of cities. A merchant has chosen some paths and wants to earn as much money as possible in each path. When he move along a path, he can choose one city to buy some goods and sell them in a city after it. The goods in all cities are the same but the prices are different. Now your task is to calculate the maximum possible profit on each path.

Input

The first line contains N, the number of cities.
Each of the next N lines contains wi the goods' price in each city.
Each of the next N-1 lines contains labels of two cities, describing a road between the two cities.
The next line contains Q, the number of paths.
Each of the next Q lines contains labels of two cities, describing a path. The cities are numbered from 1 to N.

1 ≤ NwiQ ≤ 50000

Output

The output contains Q lines, each contains the maximum profit of the corresponding path. If no positive profit can be earned, output 0 instead.

Sample Input

4
1
5
3
2
1 3
3 2
3 4
9
1 2
1 3
1 4
2 3
2 1
2 4
3 1
3 2
3 4

Sample Output

4
2
2
0
0
0
0
2
0

题意简述:

给定一个N个节点的树,1<=N<=50000 每个节点都有一个权值,代表商品在这个节点的价格。商人从某个节点a移动到节点b(规定了方向),且只能购买并出售一次商品(出售在购买之后),问最多可以产生多大的利润。

算法分析:

  • 显然任意两个城市之间的路径是唯一的,商人有方向地从起点移动到终点。询问这条路径上任意两点权值之差最大为多少,且要保证权值较大的节点在路径上位于权值较小的节点之后。
  • 暴力的方法是显而易见的,只要找到两个点的深度最深的公共祖先,就等于找到了这条路径,之后沿着路径走一遍即可找到最大的利润,然而无法满足50000的数据规模。
  • 首先考虑高效寻找LCA(公共祖先)的方法。记录ance[i][j]为节点i向上走2^j步到达的某个祖先。可以简单地列出方程 ance[i][j]=ance[ance[i][j-1]][j-1];于是找到了高效构建的方法。
  • 每次寻找LCA 首先将两个节点通过swim(a,b)函数转移到同一深度,然后每次找一个最小的j使得ance[a][j]==ance[b][j] 之后将节点a赋值为ance[a][j-1] 直到j=0就找到了两者的LCA
  • 现在我们已经找到了高效寻找LCA的方法,假设我们知道节点a到LCA的最小值minp[],LCA到节点b的最大值maxp[],
  • 以及买卖地点全在LCA之前可以获得的最大利润maxi[] 以及买卖地点全在LCA之后可以获得的最大利润maxI[] 显然就得到了最后的答案。 维护这些数据的方式类似于维护ance数组的方式,DP方程也很好列出, 这里就不给出了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=;
int dep[maxn],ance[maxn][],maxp[maxn][],minp[maxn][],maxi[maxn][];
int maxI[maxn][],price[maxn],n,fa[maxn];
int q[maxn],head,tail,Laxt[maxn<<],Next[maxn<<],To[maxn<<],cnt;
int max(int a,int b) { if(a>b) return a; return b;}
int min(int a,int b) { if(a>b) return b; return a;}
void add(int u,int v)
{
Next[++cnt]=Laxt[u];
Laxt[u]=cnt;
To[cnt]=v;
}
void BFS_build()
{
q[++tail]=;
fa[]=;
dep[]=;
while(tail>head){
int np=q[++head];
ance[np][]=fa[np];
maxp[np][]=max(price[np],price[fa[np]]);
minp[np][]=min(price[np],price[fa[np]]);
if(price[np]<price[fa[np]]) maxi[np][]=price[fa[np]]-price[np];
else maxi[np][]=;
if(price[np]>price[fa[np]]) maxI[np][]=price[np]-price[fa[np]];
else maxI[np][]=;
for(int i=;i<=;i++){ //倍增DP方程 ance[np][i]=ance[ance[np][i-]][i-];
maxp[np][i]=max(maxp[np][i-],maxp[ance[np][i-]][i-]);
minp[np][i]=min(minp[np][i-],minp[ance[np][i-]][i-]); int a=maxi[np][i-],b=maxi[ance[np][i-]][i-];
int c=maxp[ance[np][i-]][i-]-minp[np][i-];
maxi[np][i]=max(max(a,b),c);
a=maxI[np][i-]; b=maxI[ance[np][i-]][i-];c;
c=maxp[np][i-]-minp[ance[np][i-]][i-];
maxI[np][i]=max(max(a,b),c);
if(ance[np][i]==) break;
}
for(int i=Laxt[np];i;i=Next[i]){
int nv=To[i];
if(dep[nv]) continue;
fa[nv]=np;
dep[nv]=dep[np]+;
q[++tail]=nv;//q.push(nv);
}
}
}
int ia,ib,mi,ma;
int ancest;
void swim(int &a,int &b)
{
if(dep[a]==dep[b])return ;
while(dep[a]>dep[b]){
int i;
for(i=;i<=;i++) if(pow(,i)+dep[b]>dep[a]) break;
ia=max(max(ia,maxi[a][i-]),maxp[a][i-]-mi);
mi=min(mi,minp[a][i-]);
a=ance[a][i-];
}
while(dep[a]<dep[b]){
int i;
for(i=;i<=;i++) if(pow(,i)+dep[a]>dep[b])break;
ib=max(max(ib,maxI[b][i-]),ma-minp[b][i-]);
ma=max(ma,maxp[b][i-]);
b=ance[b][i-];
}
}
int solve(int a,int b)
{
ia=;ib=;mi=price[a];ma=price[b];
swim(a,b);
if(a==b)return max(max(ia,ib),ma-mi);
while(true){ int i;
for(i=;i<=;i++)
if(ance[a][i]==ance[b][i])break;
if(i==){
ancest=ance[a][];
ia=max(ia,price[ancest]-mi);
ib=max(ib,ma-price[ancest]);
mi=min(mi,price[ancest]);
ma=max(ma,price[ancest]);
return max(max(ia,ib),ma-mi);
} else{
ia=max(max(ia,maxi[a][i-]),maxp[a][i-]-mi);
ib=max(max(ib,maxI[b][i-]),ma-minp[b][i-]);
mi=min(mi,minp[a][i-]);
ma=max(ma,maxp[b][i-]);
a=ance[a][i-];b=ance[b][i-];
}
}
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&price[i]);
for(int i=;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
add(a,b); add(b,a);
}
BFS_build();
int p;
scanf("%d",&p);
for(int i=;i<=p;i++){
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",solve(a,b));
}
return ;
}

太球繁琐了。。。。题解是COPY 过来的,代码是稍微改了一下的。From:https://www.cnblogs.com/heisenberg-/p/5471202.html

然后并查集算法。。。emmm。等我智力够了来。

POJ3728The merchant (倍增)(LCA)(DP)(经典)(||并查集压缩路径?)的更多相关文章

  1. LA3027 合作网络-并查集压缩路径

    有N个结点 一次 I u v 操作表示把结点u的父结点设为v,距离为|u-v|%1000.输入保证执行指令前u没有父结点 一次E u 操作表示询问u到根结点的距离 O操作表示结束 #include&l ...

  2. HDU1232 畅通工程---(经典并查集应用)

    http://acm.hdu.edu.cn/showproblem.php?pid=1232 畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory ...

  3. POJ1182--食物链(经典并查集)并查集看不出来系列2

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 65906   Accepted: 19437 Description ...

  4. POJ 3728 The merchant(LCA+DP)

    The merchant Time Limit : 6000/3000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total ...

  5. POJ 3278:The merchant(LCA&DP)

    The merchant Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 6864   Accepted: 2375 Desc ...

  6. HDU 5652 India and China Origins(经典并查集)

    特别经典的一个题,还有一种方法就是二分+bfs 题意:空间内n*m个点,每个点是0或者1,0代表此点可以走,1代表不能走.接着经过q年,每年一个坐标表示此点不能走.问哪年开始图上不能出现最上边不能到达 ...

  7. POJ 1182 食物链(经典并查集) (多组输入有时乱加也会错!)

      多组输入有时乱加也会错! 这次用多组输入竟然,不用竟然对了,所以以后做题目,若是答案错误,先看加上或者删掉多组输入,看对不对 食物链 Time Limit: 1000MS   Memory Lim ...

  8. Codeforces Round #383 (Div. 2)D. Arpa's weak amphitheater and Mehrdad's valuable Hoses(dp背包+并查集)

    题目链接 :http://codeforces.com/contest/742/problem/D 题意:给你n个女人的信息重量w和美丽度b,再给你m个关系,要求邀请的女人总重量不超过w 而且如果邀请 ...

  9. nyoj 1022 合纵连横 经典并查集

    思路:关键在于并查集的删点操作. 给每个诸侯国一个另外的编号,比如box[i]表示诸侯国i现在处于第box[i]个联盟,可以随时改变它的联盟编号,并且让box[i] = k, 实现删除操作.以前联盟中 ...

随机推荐

  1. 缷载vs2015后项目不能加载问题

    当加载项目时出现MSBuildToolsPath is not specified for the ToolsVersion "14.0" defined at "HKE ...

  2. Android - 单例模式(singleton)的使用

    单例模式(singleton)的使用 本文地址:http://blog.csdn.net/caroline_wendy 单例(singleton)是特殊的Java类,在创建实例时.一个类仅同意创建一个 ...

  3. 汉字unicode码表范围和常用汉字unicode码

    utf-8吗表中所有汉字的区间的正则表达式[\u4e00-\u9fa5] 汉字常用字unicode吗表String base ="\u7684\u4e00\u4e86\u662f\u6211 ...

  4. 使用mysqld_multi 实现Mysql 5.6.36 + 5.7.18 单机多实例多版本安装

    Mysql 5.6.36 + 5.7.18 单机多实例多版本安装 随着硬件层面的发展,各种高性能服务器如雨后春笋般出现,但高性能服务器不免造成浪费, MySQL单机多实例,是指在一台物理服务器上运行多 ...

  5. Git分支中的远程操作实践

    Git分支中的远程操作实践 前几篇博客陆陆续续的讲了好多关于Git操作的内容, 其中在上篇博客聊了<Git中的merge.rebase.cherry-pick以及交互式rebase>,本篇 ...

  6. easyUI中 datagrid 格式化日期

    $('#List').datagrid({ url: '@Url.Action("GetList")', width:SetGridWidthSub(10), methord: ' ...

  7. Emgu安装配置及使用

    前言:项目需要,需使用图像处理来完成机械臂从运动的皮带上抓取物体的功能,所以又重拾视觉与图像处理内容. 内容:Emgu是OpenCV的一个跨平台的.NET封装,结构如下图所示: 下载地址:http:/ ...

  8. HTML--2图片热点,网页划区,拼接,表单

    图片热点: 规划出图片上的一个区域,可以做出超链接,直接点击图片区域就可以完成跳转的效果. 示例: 网页划区: 在一个网页里,规划出一个区域用来展示另一个网页的内容. 示例: 网页的拼接: 在一个网络 ...

  9. EasyPlayer windows RTSP播放器OCX插件使用说明

    鉴于大家对于EasyPlayer插件的使用还不太熟悉,特此写一篇插件的使用文档,供大家参考:EasyPlayer插件有两种,一种是基于IE的ActiveX控件,一种是基于FireFox(也支持多浏览器 ...

  10. Elipse clean后无法编译出class文件

    通常之前一直运行正常的项目,在某次修改或重新启动时总是报 ClassNotFoundException,而事实是这个类确实存在,出现这种原因最好看看 build文件下的classes是否为空 或 编译 ...