[最近公共祖先] POJ 3728 The merchant
Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 4556 | Accepted: 1576 |
Description
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 ≤ N, wi, Q ≤ 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
Source
3305 水果姐逛水果街Ⅱ
时间限制: 2 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
水果姐第二天心情也很不错,又来逛水果街。
突然,cgh又出现了。cgh施展了魔法,水果街变成了树结构(店与店之间只有一条唯一的路径)。
同样还是n家水果店,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样。
cgh给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,但不能往回走)卖出去。求最多可以赚多少钱。
水果姐向学过oi的你求助。
输入描述 Input Description
第一行n,表示有n家店
下来n个正整数,表示每家店一个苹果的价格。
下来n-1行,每行两个整数x,y,表示第x家店和第y家店有一条边。
下来一个整数m,表示下来有m个询问。
下来有m行,每行两个整数x和y,表示从第x家店出发到第y家店。
输出描述 Output Description
有m行。
每行对应一个询问,一个整数,表示面对cgh的每次询问,水果姐最多可以赚到多少钱。
样例输入 Sample Input
10
16 5 1 15 15 1 8 9 9 15
1 2
1 3
2 4
2 5
2 6
6 7
4 8
1 9
1 10
6
9 1
5 1
1 7
3 3
1 1
3 6
样例输出 Sample Output
7
11
7
0
0
15
数据范围及提示 Data Size & Hint
0<=苹果的价格<=10^8
0<n<=200000
0<m<=10000
是不是一模一样?
言归正传,题目给出后很明显是一个树形结构,而且要途径起点和目标点的最近公共祖先。
那么,如何才能顺序求出两点间的最大差呢?
我们可以想一下两点间的最大差有多少种情况。
①公共祖先到终点的最大值-起点到公共祖先的最小值
②起点到公共祖先的最大值-之后起点到公共祖先的最小值
③公共祖先到终点的最大值-之后终点到公共祖先的最小值
除了以上三种,就没有其他情况了。
其中的顺序问题比较难处理,我们可以求出公共祖先后,对起点和终点分别遍历,求出起点边的最小值和终点边的最大值,①就算解决了。
对于顺序问题,可以开四个数组,max[i][j],min[i][j]代表i到2^j的最大值和最小值。
sx[i][j],dx[i][j]代表i到2^j的顺序差的最大值,倒序差的最大值(顺序是叶子结点-根节点方向,倒序相反,由自己喜欢而定)
于是处理的过程为:
ancestor[i][j].v=ancestor[ancestor[i][j-1].v][j-1].v;
ancestor[i][j].max=max(ancestor[i][j-1].max,ancestor[ancestor[i][j-1].v][j-1].max);
ancestor[i][j].min=min(ancestor[i][j-1].min,ancestor[ancestor[i][j-1].v][j-1].min);
ancestor[i][j].sx=max(max(ancestor[i][j-1].sx,ancestor[ancestor[i][j-1].v][j-1].sx),ancestor[i][j-1].max-ancestor[ancestor[i][j-1].v][j-1].min);
ancestor[i][j].dx=max(max(ancestor[i][j-1].dx,ancestor[ancestor[i][j-1].v][j-1].dx),ancestor[ancestor[i][j-1].v][j-1].max-ancestor[i][j-1].min);
这样就可以有顺序的判断了。
附上代码:
C风格C++版
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct mp
{
int next,to;
}map[211010];
struct anc
{
int v,max,min,dx,sx;
}ancestor[151010][18];
int w[211010],frist[211010],num,dep[211010],n;
void init()
{
num=0;
memset(frist,0,sizeof(frist));
memset(map,0,sizeof(map));
memset(ancestor,0,sizeof(ancestor));
memset(w,0,sizeof(w));
memset(dep,0,sizeof(dep));
}
void add(int x,int y)
{
++num;
map[num].to=y;
map[num].next=frist[x];frist[x]=num;
}
void build(int v)
{
int i;
for(i=frist[v];i;i=map[i].next)
{
if(!dep[map[i].to])
{
ancestor[map[i].to][0].v=v;
ancestor[map[i].to][0].max=max(w[map[i].to],w[v]);
ancestor[map[i].to][0].min=min(w[map[i].to],w[v]);
ancestor[map[i].to][0].sx=w[map[i].to]-w[v];
ancestor[map[i].to][0].dx=w[v]-w[map[i].to];
dep[map[i].to]=dep[v]+1;
build(map[i].to);
}
}
}
void init_ancestor()
{
int i,j;
for(j=1;j<18;++j)
for(i=1;i<=n;++i)
if(ancestor[i][j-1].v)
{
ancestor[i][j].v=ancestor[ancestor[i][j-1].v][j-1].v;
ancestor[i][j].max=max(ancestor[i][j-1].max,ancestor[ancestor[i][j-1].v][j-1].max);
ancestor[i][j].min=min(ancestor[i][j-1].min,ancestor[ancestor[i][j-1].v][j-1].min);
ancestor[i][j].sx=max(max(ancestor[i][j-1].sx,ancestor[ancestor[i][j-1].v][j-1].sx),ancestor[i][j-1].max-ancestor[ancestor[i][j-1].v][j-1].min);
ancestor[i][j].dx=max(max(ancestor[i][j-1].dx,ancestor[ancestor[i][j-1].v][j-1].dx),ancestor[ancestor[i][j-1].v][j-1].max-ancestor[i][j-1].min);
}
}
int lca(int x,int y)
{
int i,deep;
if(dep[x]<dep[y]) swap(x,y);
deep=dep[x]-dep[y];
for(i=0;i<18;++i) if((1<<i)&deep) x=ancestor[x][i].v;
if(x==y) return x;
for(i=17;i>=0;--i)
{
if(ancestor[x][i].v!=ancestor[y][i].v)
{
x=ancestor[x][i].v;
y=ancestor[y][i].v;
}
}
return ancestor[x][0].v;
}
int main()
{
int i,v,w1,z,q,qa,qb,deep,ans=0,maxx,minx;
init();
scanf("%d",&n);
for(i=1;i<=n;++i) scanf("%d",&w[i]);
ancestor[1][0].max=ancestor[1][0].min=ancestor[1][0].dx=ancestor[1][0].sx=w[1];
for(i=0;i<n-1;++i)
{
scanf("%d%d",&v,&w1);
add(v,w1);add(w1,v);
}
dep[1]=1;
build(1);
init_ancestor();
scanf("%d",&q);
while(q--)
{
scanf("%d%d",&qa,&qb);
z=lca(qa,qb);
if(qa==qb)
{
printf("0\n");
continue;
}
deep=dep[qa]-dep[z];
maxx=-1;minx=1e9;ans=0;
if(deep>0)
for(i=0;i<18;++i)
if((1<<i)&deep)
{
ans=max(ans,ancestor[qa][i].dx);
ans=max(ans,ancestor[qa][i].max-minx);
minx=min(minx,ancestor[qa][i].min);
qa=ancestor[qa][i].v;
}
deep=dep[qb]-dep[z];
if(deep>0)
for(i=0;i<18;++i)
if((1<<i)&deep)
{
ans=max(ans,ancestor[qb][i].sx);
ans=max(ans,maxx-ancestor[qb][i].min);
maxx=max(maxx,ancestor[qb][i].max);
qb=ancestor[qb][i].v;
}
ans=max(maxx-minx,ans);
printf("%d\n",ans);
}
return 0;
}
Pascal版
const
sd:array[0..15] of longint=(1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,16384<<1);
var n,i,x,y,e,k,q,ans,maxx,mixx,z,t,j:longint;
cost,node,next,h,hi:array[-100..2050000] of longint;
v:array[-100..2005000] of boolean;
f,maxn,minn,sx,dx:array[-100..200050,0..50] of longint;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
function min(a,b:longint):longint;
begin
if a>b then exit(b) else exit(a);
end;
procedure swap(var a,b:longint);
begin
if a=b then exit;
a:=a xor b;b:=a xor b;a:=a xor b;
end;
procedure add(a,b:longint);
begin
inc(e);
next[e]:=h[a];h[a]:=e;
node[e]:=b;
end;
procedure built(x,hig:longint);
var p:longint;
begin
v[x]:=true;
p:=h[x];
hi[x]:=hig;
while p>0 do
begin
if not(v[node[p]]) then
begin
f[node[p],0]:=x;
maxn[node[p],0]:=max(cost[x],cost[node[p]]);
minn[node[p],0]:=min(cost[x],cost[node[p]]);
sx[node[p],0]:=cost[node[p]]-cost[x];
dx[node[p],0]:=cost[x]-cost[node[p]];
built(node[p],hig+1);
end;
p:=next[p];
end;
end;
function lca(a,b:longint):longint;
begin
lca:=0;
if hi[a]<hi[b] then swap(a,b);
while hi[a]>hi[b] do
begin
k:=0;
while hi[a]-hi[b]>sd[k+1] do inc(k);
a:=f[a,k];lca:=a;
end;
while a<>b do
begin
if f[a,0]=f[b,0] then exit(f[a,0]);
k:=0;
while (f[a,k+1]<>f[b,k+1]) and (hi[a]>=sd[k+1]) do inc(k);
a:=f[a,k];b:=f[b,k];lca:=a;
end;
end;
procedure init;
begin
readln(n);
for i:=1 to n do read(cost[i]);
maxn[1,0]:=cost[1];minn[1,0]:=cost[1];
sx[1,0]:=cost[1];dx[1,0]:=cost[1];
for i:=1 to n-1 do
begin
readln(x,y);
add(x,y);add(y,x);
end;
built(1,0);
k:=1;
while sd[k]<n do
begin
for i:=1 to n do
begin
if hi[i]>=sd[k] then
begin
f[i,k]:=f[f[i,k-1],k-1];
maxn[i,k]:=max(maxn[f[i,k-1],k-1],maxn[i,k-1]);
minn[i,k]:=min(minn[f[i,k-1],k-1],minn[i,k-1]);
dx[i,k]:=max(max(dx[i,k-1],dx[f[i,k-1],k-1]),maxn[f[i,k-1],k-1]-minn[i,k-1]);
sx[i,k]:=max(max(sx[i,k-1],sx[f[i,k-1],k-1]),maxn[i,k-1]-minn[f[i,k-1],k-1]);
end;
end;
inc(k);
end;
readln(q);
end;
begin
init;
for i:=1 to q do
begin
maxx:=0;mixx:=100000000;ans:=0;
readln(x,y);
if x=y then
begin
writeln(0);
continue;
end;
z:=lca(x,y);
t:=hi[x]-hi[z];
if t>0 then
begin
while hi[x]>hi[z] do
begin
k:=0;
while hi[x]-hi[z]>sd[k+1] do inc(k);
ans:=max(dx[x,k],ans);
ans:=max(ans,maxn[x,k]-mixx);
mixx:=min(mixx,minn[x,k]);
x:=f[x,k];
end;
end;
t:=hi[y]-hi[z];
if t>0 then
begin
while hi[y]>hi[z] do
begin
k:=0;
while hi[y]-hi[z]>sd[k+1] do inc(k);
ans:=max(sx[y,k],ans);
ans:=max(ans,maxx-minn[y,k]);
maxx:=max(maxx,maxn[y,k]);
y:=f[y,k];
end; end;
ans:=max(maxx-mixx,ans);
writeln(ans);
end;
end.
时间比较:
明显转了C++快多了,不过也为以前的自己点赞。
[最近公共祖先] POJ 3728 The merchant的更多相关文章
- [POJ 3728]The merchant
Description There are N cities in a country, and there is one and only one simple path between each ...
- POJ 3728 The merchant(LCA+DP)
The merchant Time Limit : 6000/3000ms (Java/Other) Memory Limit : 131072/65536K (Java/Other) Total ...
- [最近公共祖先] POJ 1330 Nearest Common Ancestors
Nearest Common Ancestors Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 27316 Accept ...
- POJ 3728 The merchant (树形DP+LCA)
题目:https://vjudge.net/contest/323605#problem/E 题意:一棵n个点的树,然后有m个查询,每次查询找(u->v)路径上的两个数,a[i],a[j],(i ...
- poj 3728 The merchant(LCA)
Description There are N cities in a country, and there is one and only one simple path between each ...
- POJ 3728 The merchant(并查集+DFS)
[题目链接] http://poj.org/problem?id=3728 [题目大意] 给出一棵树,每个点上都可以交易货物,现在给出某货物在不同点的价格, 问从u到v的路程中,只允许做一次买入和一次 ...
- poj——3728 The merchant
The merchant Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 5055 Accepted: 1740 Desc ...
- poj 3728 The merchant 倍增lca求dp
题目: zdf给出的题目翻译: 从前有一个富饶的国度,在这里人们可以进行自由的交易.这个国度形成一个n个点的无向图,每个点表示一个城市,并且有一个权值w[i],表示这个城市出售或收购这个权值的物品.又 ...
- 最近公共祖先(LCA)模板
以下转自:https://www.cnblogs.com/JVxie/p/4854719.html 首先是最近公共祖先的概念(什么是最近公共祖先?): 在一棵没有环的树上,每个节点肯定有其父亲节点和祖 ...
随机推荐
- Git 一些关于 Git、Github 的学习资源
一些关于 Git.Github 的学习资源 昨天浏览 Github 的是时候发现了 Githug 这个游戏,这个游戏用来帮助菜鸟们学习使用 Git 的. Githug is designed to g ...
- Android MimeType的用法和几种类型
关于MIME TYPE描述 多用途互联网邮件扩展(MIME,Multipurpose Internet Mail Extensions)是一个互联网标准,它扩展了电子邮件标准,使其能够支持非ASCII ...
- [转]MySQL排序原理与案例分析
这篇文章非常好,就把他转过来 前言 排序是数据库中的一个基本功能,MySQL也不例外.用户通过Order by语句即能达到将指定的结果集排序的目的,其实不仅仅是Order by语句,Grou ...
- SVN服务端启动解决方案(2013-12-10 记)
解决每一次开机都得用DOS启动SVN服务,而DOS窗口又无法关闭的情况 1.安装Setup-Subversion-1.8.5.msi搭建好SVN服务端(下载地址:http://subversion. ...
- Git入门教程
参考文献: 1. Pro Git 2. Git教程 3. Git教程 4. 图解Git
- [充电]C++ string字符串替换
//C++ 第一种替换字符串的方法用replace()|C++ 第二种替换字符串的方法用erase()和insert()[ C++string|C++ replace()|C++ erase()|C+ ...
- 图论$\cdot$最短路问题
Dijkstra单源最短路径算法 Dijkstra可以计算出发点到每个点的最短路,及单源最短路径(SSSP).这一特点使得Dijkstra常常用来进行其他算法的预处理.用Dijkstra算法计算最短路 ...
- Balanced Lineup(树状数组 POJ3264)
Balanced Lineup Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 40493 Accepted: 19035 Cas ...
- Linux命令学习整理。
http://www.cnblogs.com/suliuer/p/5448747.html 本文主要包括两部分,一是Linux基础命令的总结:二是总结一些常用的命令知识点. 一.基础总结 学习Linu ...
- CRM系统简析
寄语: 简单阐述一下对CRM系统应用的理解,此内容参考网上资料所整理. CRM是Customer Relationship Management的缩写,简称客户关系管理. CRM系统可以从三个方面来分 ...