例题来自洛谷 P1901 发射站 ,这道题普通做法需要从左向右和从右向左各来一次单调栈,能帮刚接触的学生更好的理解和练手,同时还是单调栈的模板。
再次记录模板,方便以后复习。
题目如下:
题目描述
某地有 N 个能量发射站排成一行,每个发射站 i 都有不相同的高度 Hi,并能向两边(两端的发射站只能向一边)同时发射能量值为 Vi 的能量,发出的能量只被两边最近的且比它高的发射站接收。显然,每个发射站发来的能量有可能被 0 或 1 或 2 个其他发射站所接受。
请计算出接收最多能量的发射站接收的能量是多少。
输入格式
第 1 行一个整数 N。
第 2 到 N+1 行,第 i+1 行有两个整数 Hi 和 Vi,表示第 i 个发射站的高度和发射的能量值。
输出格式
输出仅一行,表示接收最多能量的发射站接收到的能量值。答案不超过 32 位带符号整数的表示范围。
输入输出样例
输入 #1复制
3 4 2 3 5 6 10
输出 #1复制
7
说明/提示
对于 40% 的数据,1≤N≤5000,1≤Hi≤105,1≤Vi≤104。
对于 70% 的数据,1≤N≤105,1≤Hi≤2×109,1≤Vi≤104。
对于 100% 的数据,1≤N≤106,1≤Hi≤2×109,1≤Vi≤104。
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
using namespace std;
#define int long long
signed main() {
int n;
cin >> n;
vector<pair<int, int>> nums(n);
for (int i = 0; i < n; i++) {
cin >> nums[i].first >> nums[i].second;
}
// first: 高度, second: 能量
stack<int> st;
vector<int> ans(n, 0); // 存储每个发射站接收的总能量
// 从左往右遍历,找到每个发射站左边第一个比它高的发射站
for (int i = 0; i < n; i++) {
int h = nums[i].first;
while (!st.empty() && h > nums[st.top()].first) {
st.pop();
}
if (!st.empty()) {
ans[st.top()] += nums[i].second; // 将当前发射站的能量累加到左边第一个比它高的发射站
}
st.push(i);
}
// 清空栈,准备从右往左遍历
st = stack<int>();
// 从右往左遍历,找到每个发射站右边第一个比它高的发射站
for (int i = n - 1; i >= 0; i--) {
int h = nums[i].first;
while (!st.empty() && h > nums[st.top()].first) {
st.pop();
}
if (!st.empty()) {
ans[st.top()] += nums[i].second; // 将当前发射站的能量累加到右边第一个比它高的发射站
}
st.push(i);
}
// 找到接收能量最多的发射站
int maxEnergy = 0;
for (int i = 0; i < n; i++) {
if (ans[i] > maxEnergy) {
maxEnergy = ans[i];
}
}
cout << maxEnergy << endl;
return 0;
}