[
](https://www.luogu.com.cn/problem/P4147)
eg:对序列中的第 i 个元素求出该元素后面第一个大于 a[i] 的元素下标
#include <bits/stdc++.h>#define int long longusing namespace std;const int N = 3e6+5;int n;int a[N], f[N];stack<int> stk;signed main() {cin >> n;for (int i = 1; i <= n; i++)scanf("%lld", &a[i]);for (int i = n; i >= 1; i--) {while (stk.size() && a[i]>=a[stk.top()])stk.pop();f[i] = stk.size()?stk.top():0;stk.push(i);}for (int i = 1; i <= n; i++)cout << f[i] << " \n"[i==n];return 0;}
eg:直方图最大矩阵
https://www.acwing.com/problem/content/description/133/
维护一个升序的单调栈,从前往后遍历,当遇到当前方块高度小于上一个方块高度时,找到前面第一个高度小于当前方块的方块,因为中间的方块一定是单调上升的形式,所以可以将中间的连续方块按如下处理(从后往前每次计算出当前高度乘上比他高的方块的宽度累加,不断更新最大值即可),然后让当前方块的宽加上被弹出栈的方块宽度之和
对于最后剩下的单调部分,像前面一样处理即可
#include <bits/stdc++.h>#define int long longusing namespace std;const int N = 1e5+5;int a[N];struct node {int h, w;};signed main() {int n;while (cin >> n, n) {int ans = 0;for (int i = 1; i <= n; i++)scanf("%lld", &a[i]);stack<node> stk;stk.push({a[1], 1});int tmp = 0, mx = 0;for (int i = 2; i <= n; i++) {tmp = 0;while (stk.size() && stk.top().h>=a[i]) {tmp += stk.top().w;mx = max(mx, stk.top().h*tmp);stk.pop();}stk.push({a[i], tmp+1});}tmp = 0;while (stk.size()) {tmp += stk.top().w;mx = max(mx, stk.top().h*tmp);stk.pop();}ans = max(ans, mx);cout << ans << '\n';}return 0;}
eg:接雨水
https://www.acwing.com/problem/content/description/1576/
维护一个降序的单调栈,弹出所有比当前方块高度低的方块,若弹出方块候前面还有方块则累加雨水量
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
int a[N];
signed main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
int ans = 0;
stack<int> stk;
for (int i = 1; i <= n; i++) {
while (stk.size() && a[i]>a[stk.top()]) {
int tmp = stk.top();
stk.pop();
if (stk.size()) {
int len = i-stk.top()-1;
int h = min(a[i], a[stk.top()])-a[tmp];
ans += len*h;
}
}
stk.push(i);
}
cout << ans << '\n';
return 0;
}
