poj 3728 The merchant(LCA)

本文介绍了一种利用离线LCA(最近公共祖先)的算法来解决路径最大收益问题,即在一个树状结构的国家中,商人如何在不同城市间移动以实现最大的商品交易利润。通过离线查询处理和动态更新路径上的最大值与最小值,该方法能够快速准确地计算出每条路径的最大可能收益。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

 
 
转自:http://m.blog.youkuaiyun.com/blog/sdj222555/43003179
 

题意很简单

给一个树(n < 5w) 每个点有个权值,代表商品价格

若干个询问(5w)

 

对每个询问,问的是从u点走到v点(简单路径),商人在这个路径中的某点买入商品,然后在某点再卖出商品,   最大可能是多少

注意一条路径上只能买卖一次,先买才能卖

 

用的方法是离线LCA,在上面加了一些东西

对于一个询问, 假设u,v的LCA是f

那么有三种可能, 一个是从u到f 买卖了。 一个是从f到v买卖了,  一个是从u到f之间买了,从v到f卖了

从u到f 我们称为up,  从f到v我们称为down,而从u到f买然后在f到v卖就是求u到f的最小值和f到v的最大值。

 

我们要分别求这三个值

实际上就是在离线tarjan求LCA的过程中求出的

对于每个点, 我们进行dfs的时候,查看于其相关的询问,

假设当前点是u, 询问的点是v, u和v的LCA是f,如果v已经dfs过了,说明v在并查集中的祖先就是u,v的LCA  f点, 

将该询问加入到f的相关集合中,等f所有的子节点都处理过后再去处理f, 就可以发现,一切都是顺其自然了

在这些处理过程中,up和down以及u,v到f的最大值最小值  都可以在并查集求压缩路径的过程中更新。

 

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <vector>
 5 #include <queue>
 6 #include <cmath>
 7 #include <algorithm>
 8 #include <map>
 9 #include <ctime>
10 #define MAXN 52222
11 #define MAXM 222222
12 #define INF 1000000001
13 using namespace std;
14 vector<int>g[MAXN], st[MAXN], ed[MAXN], id[MAXN], ask[MAXN], pos[MAXN];
15 int mx[MAXN], mi[MAXN], up[MAXN], down[MAXN], vis[MAXN], fa[MAXN], ans[MAXN];
16 int n, Q;
17 int find(int x) {
18     if(x == fa[x]) return x;
19     int y = fa[x];
20     fa[x] = find(y);
21     up[x] = max(up[x], max(mx[y] - mi[x], up[y]));
22     down[x] = max(down[x], max(mx[x] - mi[y], down[y]));
23     mx[x] = max(mx[x], mx[y]);
24     mi[x] = min(mi[x], mi[y]);
25     return fa[x];
26 }
27 void tarjan(int u) {
28     vis[u] = 1;
29     for(int i = 0; i < ask[u].size(); i++) {
30         int v = ask[u][i];
31         if(vis[v]) {
32             int t = find(v);
33             int z = pos[u][i];
34             if(z > 0) {
35                 st[t].push_back(u);
36                 ed[t].push_back(v);
37                 id[t].push_back(z);
38             } else {
39                 st[t].push_back(v);
40                 ed[t].push_back(u);
41                 id[t].push_back(-z);
42             }
43         }
44     }
45     for(int i = 0; i < g[u].size(); i++) {
46         int v = g[u][i];
47         if(!vis[v]) {
48             tarjan(v);
49             fa[v] = u;
50         }
51     }
52     for(int i = 0; i < st[u].size(); i++) {
53         int a = st[u][i];
54         int b = ed[u][i];
55         int t = id[u][i];
56         find(a);
57         find(b);
58         ans[t] = max(up[a], max(down[b], mx[b] - mi[a]));
59     }
60 }
61 
62 int main() {
63         scanf("%d", &n);
64         int u, v, w;
65 
66         for(int i = 1; i <= n; i++) {
67             scanf("%d", &w);
68             mx[i] = mi[i] = w; fa[i] = i;
69         }
70         for(int i = 1; i < n; i++) {
71             scanf("%d%d", &u, &v);
72             g[u].push_back(v);
73             g[v].push_back(u);
74 
75         }
76         scanf("%d", &Q);
77         for(int i = 1; i <= Q; i++) {
78             scanf("%d%d", &u, &v);
79             ask[u].push_back(v);
80             pos[u].push_back(i);
81             ask[v].push_back(u);
82             pos[v].push_back(-i);
83         }
84         tarjan(1);
85         for(int i = 1; i <= Q; i++) printf("%d\n", ans[i]);
86 
87     return 0;
88 }
View Code

 

1. 用户与身体信息管理模块 用户信息管理: 注册登录:支持手机号 / 邮箱注册,密码加密存储,提供第三方快捷登录(模拟) 个人资料:记录基本信息(姓名、年龄、性别、身高、体重、职业) 健康目标:用户设置目标(如 “减重 5kg”“增肌”“维持健康”)及期望周期 身体状态跟踪: 体重记录:定期录入体重数据,生成体重变化曲线(折线图) 身体指标:记录 BMI(自动计算)、体脂率(可选)、基础代谢率(根据身高体重估算) 健康状况:用户可填写特殊情况(如糖尿病、过敏食物、素食偏好),系统据此调整推荐 2. 膳食记录与食物数据库模块 食物数据库: 基础信息:包含常见食物(如米饭、鸡蛋、牛肉)的名称、类别(主食 / 肉类 / 蔬菜等)、每份重量 营养成分:记录每 100g 食物的热量(kcal)、蛋白质、脂肪、碳水化合物、维生素、矿物质含量 数据库维护:管理员可添加新食物、更新营养数据,支持按名称 / 类别检索 膳食记录功能: 快速记录:用户选择食物、输入食用量(克 / 份),系统自动计算摄入的营养成分 餐次分类:按早餐 / 午餐 / 晚餐 / 加餐分类记录,支持上传餐食照片(可选) 批量操作:提供常见套餐模板(如 “三明治 + 牛奶”),一键添加到记录 历史记录:按日期查看过往膳食记录,支持编辑 / 删除错误记录 3. 营养分析模块 每日营养摄入分析: 核心指标计算:统计当日摄入的总热量、蛋白质 / 脂肪 / 碳水化合物占比(按每日推荐量对比) 微量营养素分析:检查维生素(如维生素 C、钙、铁)的摄入是否达标 平衡评估:生成 “营养平衡度” 评分(0-100 分),指出摄入过剩或不足的营养素 趋势分析: 周 / 月营养趋势:用折线图展示近 7 天 / 30 天的热量、三大营养素摄入变化 对比分析:将实际摄入与推荐量对比(如 “蛋白质摄入仅达到推荐量的 70%”) 目标达成率:针对健
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值