题意简述:给定一个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>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int maxn=50000+10;
vector<int>po[maxn];
int dep[maxn],ance[maxn][17],maxp[maxn][17],minp[maxn][17],maxi[maxn][17],maxI[maxn][17],price[maxn],n,fa[maxn];
bool vis[maxn];
int max(int a,int b)
{
if(a>b)return a;
else return b;
}
int min(int a,int b)
{
if(a>b)return b;
else return a;
}
queue<int> q;
void BFS_build()
{
memset(vis,0,sizeof(vis)); q.push(1);
fa[1]=1;
dep[1]=1;
vis[1]=true;
while(!q.empty())
{
int np=q.front();q.pop();
ance[np][0]=fa[np];
maxp[np][0]=max(price[np],price[fa[np]]);
minp[np][0]=min(price[np],price[fa[np]]);
if(price[np]<price[fa[np]])maxi[np][0]=price[fa[np]]-price[np];
else maxi[np][0]=0;
if(price[np]>price[fa[np]])maxI[np][0]=price[np]-price[fa[np]];
else maxI[np][0]=0;
for(int i=1;i<=16;i++)//倍增DP方程
{
ance[np][i]=ance[ance[np][i-1]][i-1];
maxp[np][i]=max(maxp[np][i-1],maxp[ance[np][i-1]][i-1]);
minp[np][i]=min(minp[np][i-1],minp[ance[np][i-1]][i-1]);
int a=maxi[np][i-1],b=maxi[ance[np][i-1]][i-1],c=0;
c=maxp[ance[np][i-1]][i-1]-minp[np][i-1];
maxi[np][i]=max(max(a,b),c);
a=maxI[np][i-1];b=maxI[ance[np][i-1]][i-1];c;
c=maxp[np][i-1]-minp[ance[np][i-1]][i-1];
maxI[np][i]=max(max(a,b),c);
if(ance[np][i]==1)break;
}
for(int i=0;i<po[np].size();i++)
{
int nv=po[np][i];
if(vis[nv])continue;
fa[nv]=np;
dep[nv]=dep[np]+1;
q.push(nv);
vis[nv]=true;
}
}
}
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=0;i<=16;i++)
{
if(pow(2,i)+dep[b]>dep[a])break;
}
ia=max(max(ia,maxi[a][i-1]),maxp[a][i-1]-mi);
mi=min(mi,minp[a][i-1]);
a=ance[a][i-1];
}
while(dep[a]<dep[b])
{
int i;
for(i=0;i<=16;i++)
{
if(pow(2,i)+dep[a]>dep[b])break;
}
ib=max(max(ib,maxI[b][i-1]),ma-minp[b][i-1]);
ma=max(ma,maxp[b][i-1]);
b=ance[b][i-1];
}
}
int solve(int a,int b)
{
ia=0;ib=0;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=0;i<=16;i++)
{
if(ance[a][i]==ance[b][i])break;
}
if(i==0)
{
ancest=ance[a][0];
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-1]),maxp[a][i-1]-mi);
ib=max(max(ib,maxI[b][i-1]),ma-minp[b][i-1]);
mi=min(mi,minp[a][i-1]);
ma=max(ma,maxp[b][i-1]);
a=ance[a][i-1];b=ance[b][i-1];
}
} }
int main()
{freopen("t.txt","r",stdin);
scanf("%d",&n); for(int i=1;i<=n;i++)
scanf("%d",&price[i]);
for(int i=1;i<n;i++)
{
int a,b;
scanf("%d%d",&a,&b);
po[a].push_back(b);po[b].push_back(a);
}
BFS_build();
int p;
scanf("%d",&p);
for(int i=1;i<=p;i++)
{
int a,b;
scanf("%d%d",&a,&b);
printf("%d\n",solve(a,b));
}
return 0;
}

  这个题目似乎是北大月赛的题目,不得不佩服他们题目的质量,渣校只能仰望了。

POJ3728 LCA RMQ DP的更多相关文章

  1. POJ3728 THE MERCHANT LCA RMQ DP

    题意简述:给定一个N个节点的树,1<=N<=50000 每个节点都有一个权值,代表商品在这个节点的价格.商人从某个节点a移动到节点b,且只能购买并出售一次商品,问最多可以产生多大的利润. ...

  2. POJ 1470 Closest Common Ancestors(LCA&RMQ)

    题意比较费劲:输入看起来很麻烦.处理括号冒号的时候是用%1s就可以.还有就是注意它有根节点...Q次查询 在线st算法 /*************************************** ...

  3. CDOJ 92 Journey(LCA&RMQ)

    题目连接:http://acm.uestc.edu.cn/#/problem/show/92 题意:给定一棵树,最后给加一条边,给定Q次查询,每次查询加上最后一条边之后是否比不加这条边要近,如果近的话 ...

  4. 【Homework】LCA&RMQ

    我校是神校,作业竟然选自POJ,难道不知道“珍爱生命 勿刷POJ”么? 所有注明模板题的我都十分傲娇地没有打,于是只打了6道题(其实模板题以前应该打过一部分但懒得找)(不过感觉我模板还是不够溜要找个时 ...

  5. POJ3417 LCA+树dp

    http://poj.org/problem?id=3417 题意:先给出一棵无根树,然后下面再给出m条边,把这m条边连上,然后每次你能毁掉两条边,规定一条是树边,一条是新边,问有多少种方案能使树断裂 ...

  6. 算法详解(LCA&RMQ&tarjan)补坑啦!完结撒花(。◕ˇ∀ˇ◕)

    首先,众所周知,求LCA共有3种算法(树剖就不说了,太高级,以后再学..). 1.树上倍增(ST表优化) 2.RMQ&时间戳(ST表优化) 3.tarjan(离线算法)不讲..(后面补坑啦!) ...

  7. POJ 2763 (LCA +RMQ+树状数组 || 树链部分) 查询两点距离+修改边权

    题意: 知道了一颗有  n 个节点的树和树上每条边的权值,对应两种操作: 0 x        输出 当前节点到 x节点的最短距离,并移动到 x 节点位置 1 x val   把第 x 条边的权值改为 ...

  8. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  9. UESTC 912 树上的距离 --LCA+RMQ+树状数组

    1.易知,树上两点的距离dis[u][v] = D[u]+D[v]-2*D[lca(u,v)] (D为节点到根节点的距离) 2.某条边<u,v>权值一旦改变,将会影响所有以v为根的子树上的 ...

随机推荐

  1. libthread_db

    http://timetobleed.com/notes-about-an-odd-esoteric-yet-incredibly-useful-library-libthread_db/

  2. OPENCV之GFTT特征点检测

    之前角点检测的时候提到过角点检测的算法,第一个是cornerHarris计算角点,但是这种角点检测算法容易出现聚簇现象以及角点信息有丢失和位置偏移现象,所以后面又提出一种名为 shi_tomasi的角 ...

  3. EQueue - 一个C#写的开源分布式消息队列的总体介绍(转)

    源: EQueue - 一个C#写的开源分布式消息队列的总体介绍 EQueue - 一个纯C#写的分布式消息队列介绍2 EQueue - 详细谈一下消息持久化以及消息堆积的设计

  4. iOS-模糊查询

    http://blog.csdn.net/qq_33701006/article/details/51836914 版权声明:本文为博主原创文章,未经博主允许不得转载.   目录(?)[+]   前言 ...

  5. R语言实战(四)回归

    本文对应<R语言实战>第8章:回归 回归是一个广义的概念,通指那些用一个或多个预测变量(也称自变量或解释变量)来预测响应变量(也称因变量.效标变量或结果变量)的方法.通常,回归分析可以用来 ...

  6. 组织Golang代码

    本月初golang官方blog(需要自己搭梯子)上发布了一篇文章,简要介绍了近几个月Go在一 些技术会议上(比如Google I/O.Gopher SummerFest等)的主题分享并伴有slide链 ...

  7. CocoaPods安装和使用教程 分类: ios技术 ios相关 2015-03-11 21:53 48人阅读 评论(0) 收藏

    目录 CocoaPods是什么? 如何下载和安装CocoaPods? 如何使用CocoaPods? 场景1:利用CocoaPods,在项目中导入AFNetworking类库 场景2:如何正确编译运行一 ...

  8. python内置函数all使用的坑

    在代码的改造过程中,因为忽略了一个问题导致数据异常,在改造的过程中以及后续的review中都没注意到这个问题,单元测试也没有覆盖到,记录如下.这个坑在于all的使用上,如果参数为空元组或空列表时,返回 ...

  9. RoundedImageView使用吐槽心得(RoundedImageView与Glide加载图片,第一次加载无法圆角问题)

    最近使用的时候发现一个问题, RoundedImageView与Glide搭配使用的时候,第一次加载图片(内存中没有),后图片无法圆角,后来尝试各种改,最后想到了一个办法,就是让Glide加载图片的 ...

  10. IOS软件国际化(本地化Localizable)

    IOS软件国际化(本地化Localizable) iPhone是支持语言最多的手机,它支持各国语言及中国少数名族如蒙古等语言,这也是好多少数名族都用苹果的原因.在这一点上我们自主品牌还是要多学习学习. ...