【模板】单调栈
题目背景
模板题,无背景。
2019.12.12 更新数据,放宽时限,现在不再卡常了。
题目描述
给出项数为 n n n 的整数数列 a 1 … n a_{1 \dots n} a1…n。
定义函数 f ( i ) f(i) f(i) 代表数列中第 i i i 个元素之后第一个大于 a i a_i ai 的元素的下标,即 f ( i ) = min i < j ≤ n , a j > a i { j } f(i)=\min_{i<j\leq n, a_j > a_i} \{j\} f(i)=mini<j≤n,aj>ai{j}。若不存在,则 f ( i ) = 0 f(i)=0 f(i)=0。
试求出 f ( 1 … n ) f(1\dots n) f(1…n)。
输入格式
第一行一个正整数 n n n。
第二行 n n n 个正整数 a 1 … n a_{1\dots n} a1…n。
输出格式
一行 n n n 个整数表示 f ( 1 ) , f ( 2 ) , … , f ( n ) f(1), f(2), \dots, f(n) f(1),f(2),…,f(n) 的值。
样例 #1
样例输入 #1
5
1 4 2 3 5
样例输出 #1
2 5 4 5 0
提示
【数据规模与约定】
对于 30 % 30\% 30% 的数据, n ≤ 100 n\leq 100 n≤100;
对于 60 % 60\% 60% 的数据, n ≤ 5 × 1 0 3 n\leq 5 \times 10^3 n≤5×103 ;
对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 3 × 1 0 6 1 \le n\leq 3\times 10^6 1≤n≤3×106, 1 ≤ a i ≤ 1 0 9 1\leq a_i\leq 10^9 1≤ai≤109。
思路
首先,定义一个数组 a a a和 f f f,以及一个栈 s t k stk stk。数组 a a a用于存储输入的数列,数组 f f f用于存储每个元素后面第一个比它大的元素的下标。
在主函数中,首先读取数列的长度 n n n,然后读取数列的每个元素,存储在数组 a a a中。然后,对于数列中的每一个元素,检查栈顶元素是否小于当前元素。如果是,则更新栈顶元素在数组 f f f中的值为当前元素的下标,并弹出栈顶元素。然后将当前元素的下标入栈。这样,栈中的元素总是保持单调递减的顺序,即栈顶元素总是栈中最小的元素。
最后,输出数组 f f f中的每一个元素,即每个元素后面第一个比它大的元素的下标。
注意 :
- 因为要找的是第 i i i 个元素之后第一个大于 a i a_i ai 的元素的下标,所以要往栈里存下标而不是元素的数值。
- 可能会出现重复数据。因为要找的是第
i
i
i 个元素之后第一个大于
a
i
a_i
ai 的元素的下标,所以当
a[stk.top()] < a[i]
时出栈。如果写成a[stk.top()] <= a[i]
,会报WA,只能得60分。警钟撅烂!!!
AC代码
#include <algorithm>
#include <iostream>
#include <stack>
#define AUTHOR "HEX9CF"
using namespace std;
const int N = 1e7 + 7;
int n;
int a[N], f[N];
stack<int> stk;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
while (stk.size() && a[stk.top()] < a[i]) {
f[stk.top()] = i;
stk.pop();
}
stk.push(i);
}
for (int i = 1; i <= n; i++) {
cout << f[i] << " ";
}
return 0;
}