【模板】单调栈(P5788)

题目

题目描述:

给出项数为 nn 的整数数列 a1na_{1 \dots n}

定义函数 f(i)f(i) 代表数列中第 ii 个元素之后第一个大于 aia_i 的元素的下标,即 f(i)=mini<jn,aj>ai{j}f(i)=\min_{i<j\leq n, a_j > a_i} \{j\}。若不存在,则 f(i)=0f(i)=0

试求出 f(1n)f(1\dots n)

输入格式:

第一行一个正整数 nn

第二行 nn 个正整数 a1na_{1\dots n}

输出格式:

一行 nn 个整数表示 f(1),f(2),,f(n)f(1), f(2), \dots, f(n) 的值。

数据范围与说明:

【数据规模与约定】

对于 30%30\% 的数据,n100n\leq 100

对于 60%60\% 的数据,n5×103n\leq 5 \times 10^3

对于 100%100\% 的数据,1n3×1061 \le n\leq 3\times 10^61ai1091\leq a_i\leq 10^9

输入输出样例 #1

输入:

1
2
5
1 4 2 3 5

输出:

1
2 5 4 5 0

题意

给定一个长度为 nn 的序列 aa,定义 f(i)f(i) 为第 ii 个元素之后第一个严格大于 aia_i 的元素下标,不存在则为 00。输出 f(1n)f(1\ldots n)

思路

从右向左维护“严格递减”的单调栈:

  • 栈中存储下标,且对应的值严格递减;
  • 对于当前位置 ii,不断弹出小于等于 aia_i 的下标,剩余的栈顶即为第一个更大的位置;
  • 若栈为空,则 f(i)=0f(i)=0
  • 处理完后将 ii 入栈继续向左。

时间复杂度 O(n)O(n)

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <bits/stdc++.h>
using namespace std;

const int N = 3'000'000 + 5;
int a[N], ans[N];

int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);

int n;
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];

stack<int> st;
for (int i = n; i >= 1; --i) {
while (!st.empty() && a[st.top()] <= a[i]) st.pop();
ans[i] = st.empty() ? 0 : st.top();
st.push(i);
}

for (int i = 1; i <= n; ++i) {
cout << ans[i] << (i == n ? '\n' : ' ');
}
return 0;
}