《P3976 [TJOI2015] 旅游》
题目描述
为了提高智商,ZJY 准备去往一个新世界去旅游。这个世界的城市布局像一棵树,每两座城市之间只有一条路径可以互达。
每座城市都有一种宝石,有一定的价格。ZJY 为了赚取最高利益,她会选择从 A 城市买入再转手卖到 B 城市。
由于ZJY买宝石时经常卖萌,因而凡是 ZJY 路过的城市,这座城市的宝石价格会上涨。让我们来算算 ZJY 旅游完之后能够赚取的最大利润。(如 A 城市宝石价格为 v,则ZJY出售价格也为 v)
输入格式
第一行输入一个正整数 n 表示城市个数
接下来一行输入 n 个正整数表示每座城市宝石的最初价格 p,每个宝石的初始价格不超过 100。
第三行开始连续输入 n−1 行,每行有两个数字 x 和 y。表示 x 城市和 y 城市有一条路径。城市编号从1开始。
下一行输入一个正整数 q 表示询问次数。
接下来 q 行每行输入三个正整数 a,b,v,表示 ZJY 从 a 旅游到 b,城市宝石上涨 v。
输出格式
对于每次询问,输出 ZJY 可能获得的最大利润,如果亏本了则输出 0。
输入输出样例
输入 #1复制
3 1 2 3 1 2 2 3 2 1 2 100 1 3 100
输出 #1复制
1 1
输入 #2复制
5 1 2 3 4 5 1 2 1 3 2 4 4 5 6 1 5 50 2 4 500 3 4 5000 3 5 50000 1 3 500000 2 3 5000000
输出 #2复制
4 2 551 551 0 499499
说明/提示
数据规模与约定
- 对于 30% 的数据,保证 n≤100,q≤104。
- 对于 100% 的数据,保证 1≤n,q≤5×104,在任何时刻任何城市的宝石价格都不超过 109。
代码实现:
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
vector<vector<int> > adj; // 邻接表表示树
vector<int> prices; // 各城市宝石价格
vector<bool> visited; // 标记访问状态
vector<int> path; // 存储A到B的路径
// 深度优先搜索寻找从start到end的路径
bool dfs(int start, int end) {
visited[start] = true;
path.push_back(start);
// 找到目标城市
if (start == end) {
return true;
}
// 探索相邻城市(改用下标遍历)
for (int i = 0; i < adj[start].size(); i++) {
int next = adj[start][i]; // 获取第i个邻接城市
if (!visited[next]) {
if (dfs(next, end)) {
return true;
}
}
}
// 若未找到,回溯
path.pop_back();
return false;
}
int main() {
int n;
cin >> n;
prices.resize(n + 1);
adj.resize(n + 1);
// 输入初始价格
for (int i = 1; i <= n; i++) {
cin >> prices[i];
}
// 输入树的边
for (int i = 0; i < n - 1; i++) {
int x, y;
cin >> x >> y;
adj[x].push_back(y);
adj[y].push_back(x);
}
int q;
cin >> q;
// 处理每次询问
while (q--) {
int a, b, v;
cin >> a >> b >> v;
// 寻找a到b的路径
visited.assign(n + 1, false);
path.clear();
dfs(a, b);
// 计算最大利润
int maxProfit = 0;
int minPrice = prices[path[0]];
// 遍历路径计算利润(同样改用下标遍历)
for (int i = 1; i < path.size(); i++) {
int currentCity = path[i];
int currentProfit = prices[currentCity] - minPrice;
if (currentProfit > maxProfit) {
maxProfit = currentProfit;
}
if (prices[currentCity] < minPrice) {
minPrice = prices[currentCity];
}
}
// 输出最大利润(不小于0)
cout << max(maxProfit, 0) << endl;
// 更新路径上所有城市的宝石价格(下标遍历)
for (int i = 0; i < path.size(); i++) {
int city = path[i];
prices[city] += v;
}
}
return 0;
}