poj3728The merchant 【倍增】【LCA】
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
倍增 LCA还是完全不会写.....
所以是看的题解
刚开始完全不能理解为什么这道题也能转换成LCA 找得到公共祖先然后呢 然后呢 然后呢
建的图相当于一个dfs树 路径是唯一的
找公共祖先t就相当于找到这条路径 公共祖先把这个路径分成了两半
最后(u, v)的答案有三种可能
1.u到t完成了买和卖
2.t到v完成了买和卖
3.在u到t某点买,t到v某点卖
因此现在需要一个up数组,up[i][j]维护i到i节点往上2^j的节点的最大差价
down数组,down[i][j]维护i到i节点往下2^j的节点的最大差价
Max数组, Max[i][j]维护i到i节点往上2^j的节点之间价格的最大值
Min数组,Min[i][j]维护i到i节点往上2^j的节点之间价格的最小值
parent数组,parent[i][0]存储每个节点的父亲,用dfs先预处理出来。用倍增的思想处理出parent[i][j]表示i往上2^j的节点
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <cstring>
#include <vector>
#include <map>
#include <set>
#include <stdio.h>
#include <queue>
#include <stack>
#define inf 0x3f3f3f3f
using namespace std;
int n, q, ecnt;
const int maxn = 50005;
int Max[maxn][20], Min[maxn][20], up[maxn][20], down[maxn][20], parent[maxn][20];
vector <int> g[maxn];
int dep[maxn],val[maxn];
void dfs(int u, int fa)
{
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i];
if(v == fa) continue;
dep[v] = dep[u] + 1;
parent[v][0] = u;
Max[v][0] = max(val[v], val[u]);
Min[v][0] = min(val[v], val[u]);
down[v][0] = max(0, val[v] - val[u]);
up[v][0] = max(0, val[u] - val[v]);
dfs(v, u);
}
}
void init()
{
dep[1] = 1;
memset(parent, -1, sizeof(parent));
dfs(1, 0);
for(int j = 1; (1 << j) <= n; j++){
for(int i = 1; i <= n; i++){
if(~parent[i][j - 1]){
int k = parent[i][j - 1], a, b;
parent[i][j] = parent[k][j - 1];
Max[i][j] = max(Max[i][j - 1], Max[k][j - 1]);
Min[i][j] = min(Min[i][j - 1], Min[k][j - 1]);
a = max(0, Max[i][j - 1] - Min[k][j - 1]), b = max(down[i][j - 1], down[k][j - 1]);
down[i][j] = max(a, b);
a = max(0, Max[k][j - 1] - Min[i][j - 1]), b = max(up[i][j - 1], up[k][j - 1]);
up[i][j] = max(a,b);
}
}
}
}
int LCA(int a, int b)
{
if(dep[a] < dep[b]) swap(a, b);
int i;
for(i = 0; (1 << i) <= dep[a]; i++);
i--;
for(int j = i; j >= 0; j--){
if(dep[a] - (1 << j) >= dep[b]){
a = parent[a][j];
}
}
if(a == b){
return a;
}
for(int j = i; j >= 0; j--){
if(parent[a][j] != -1 && parent[a][j] != parent[b][j]){
a = parent[a][j];
b = parent[b][j];
}
}
return parent[a][0];
}
int query_down(int x, int k, int &max_val)
{
int ans = 0;
max_val = 0;
for(int i = 18; i >= 0; i--){
if(k & (1 << i)){
ans = max(ans, down[x][i]);
ans = max(ans, max_val - Min[x][i]);
max_val = max(max_val, Max[x][i]);
x = parent[x][i];
}
}
return ans;
}
int query_up(int x, int k, int &min_val)
{
int ans = 0;
min_val = inf;
for(int i = 18; i >= 0; i--){
if(k & (1 << i)){
ans = max(ans, up[x][i]);
ans = max(ans, Max[x][i] - min_val);
min_val = min(min_val, Min[x][i]);
x = parent[x][i];
}
}
return ans;
}
int main()
{
while(scanf("%d", &n) != EOF){
for(int i = 1; i <= n; i++){
scanf("%d", &val[i]);
}
for(int i = 1; i <= n; i++){
g[i].clear();
}
for(int i = 1; i < n; i++){
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back(v);
g[v].push_back(u);
}
init();
scanf("%d", &q);
while(q--){
int u, v;
scanf("%d%d", &u, &v);
int t = LCA(u, v);
int min_val, max_val, a, b;
a = query_up(u, dep[u] - dep[t], min_val);
b = query_down(v, dep[v] - dep[t], max_val);
int ans = max(max(0, max_val - min_val), max(a, b));
cout<<ans<<endl;
}
}
return 0;
}
poj3728The merchant 【倍增】【LCA】的更多相关文章
- POJ3728The merchant (倍增)(LCA)(DP)(经典)(||并查集压缩路径?)
There are N cities in a country, and there is one and only one simple path between each pair of citi ...
- poj 3728 The merchant 倍增lca求dp
题目: zdf给出的题目翻译: 从前有一个富饶的国度,在这里人们可以进行自由的交易.这个国度形成一个n个点的无向图,每个点表示一个城市,并且有一个权值w[i],表示这个城市出售或收购这个权值的物品.又 ...
- [板子]倍增LCA
倍增LCA板子,没有压行,可读性应该还可以.转载请随意. #include <cstdio> #include <cstring> #include <algorithm ...
- 洛谷P3128 [USACO15DEC]最大流Max Flow [倍增LCA]
题目描述 Farmer John has installed a new system of pipes to transport milk between the stalls in his b ...
- Gym100685G Gadget Hackwrench(倍增LCA)
题目大概说一棵边有方向的树,q个询问,每次询问结点u是否能走到v. 倍增LCA搞即可: 除了par[k][u]表示u结点往上走2k步到达的结点, 再加上upp[k][u]表示u结点往上走2k步经过边的 ...
- Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]
题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_di ...
- hdu 4674 Trip Advisor(缩点+倍增lca)
花了一天半的时间,才把这道题ac= = 确实是道好题,好久没敲这么长的code了,尤其是最后的判定,各种销魂啊~ 题目中给出的条件最值得关注的就是:每个点最多只能在一个环内->原图是由一个个边连 ...
- Tsinsen A1505. 树(张闻涛) 倍增LCA,可持久化线段树,DFS序
题目:http://www.tsinsen.com/A1505 A1505. 树(张闻涛) 时间限制:1.0s 内存限制:512.0MB 总提交次数:196 AC次数:65 平均分: ...
- codevs 1036 商务旅行 (倍增LCA)
/* 在我还不知道LCA之前 暴力跑的SPFA 70分 三个点TLE */ #include<iostream> #include<cstdio> #include<cs ...
随机推荐
- Strict Mode (JavaScript)
摘要: ECMAScript5中引入的严格模式,通过让JavaScript运行环境对一些开发过程中最常见和不易发现的错误做出和当前不同的处理,来让开发者拥有一个”更好”的JavaScript语言.但目 ...
- linux 实时查看Tomcat日志信息
cd /../tomcat/logs 进入tomcat/logs/文件夹下 # tail -f catalina.out
- Python基础教程学习笔记:第一章 基础知识
Python基础教程 第二版 学习笔记 1.python的每一个语句的后面可以添加分号也可以不添加分号:在一行有多条语句的时候,必须使用分号加以区分 2.查看Python版本号,在Dos窗口中输入“p ...
- SQL利用CASE按分组显示合计
按行显示的合计 select game, sum(purchase) as purchase_sum from purchase group by game; 按列显示的合计 select sum(c ...
- java命令启动jar包
本人对这些命令也是一知半解,记录备用. 1. 使用java命令行执行java文件 # 设置命令窗口标题 title test1 # 开启输出 @echo on # 设置环境变量JAVA_HOME se ...
- PostgreSQL存储过程(5)-异常错误处理
1. 异常错误处理 在PL/pgSQL函数中,如果没有异常捕获,函数会在发生错误时直接退出,与其相关的事物也会随之回滚.我们可以通过使用带有EXCEPTION子句的BEGIN块来捕获异常并使其从中恢复 ...
- 查看一个dll是否是强命名[C#]
使用命令行工具SDK Command Prompt,键入:SN -T C:\*****.dll 就会显示出该dll具体的PublicKeyToken 数值. 如果该程序集没有强命名,则不会有Publi ...
- Explaining Delegates in C# - Part 4 (Asynchronous Callback - Way 1)
So far, I have discussed about Callback, Multicast delegates, Events using delegates, and yet anothe ...
- Ubuntu图形界面和字符界面转换、指定默认启动界面
1.按ALT+CTRL+F1.F2.F3.F4.F5.F6.F7可来回切换7个界面(Linux实体机) 其中ALT+CTRL+F7可切换到图形界面(Linux实体机) 如果是V ...
- PC 商城扫描二维码登录
需求分析: 扫码入口,在pc登录首页新增二维码登录入口 点击扫码入口显示二维码 二维码有效时间为一分钟 超时后显示二维码失效,点击刷新后生成新的二维码 在app端用户登录并扫码后,点击确认登录,进行跳 ...