【洛谷 P5788】【模板】单调栈 题解(栈+单调栈)

23 阅读2分钟

【模板】单调栈

题目背景

模板题,无背景。

2019.12.12 更新数据,放宽时限,现在不再卡常了。

题目描述

给出项数为 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) 的值。

样例 #1

样例输入 #1

5
1 4 2 3 5

样例输出 #1

2 5 4 5 0

提示

【数据规模与约定】

对于 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


思路

首先,定义一个数组aaff,以及一个栈stkstk。数组aa用于存储输入的数列,数组ff用于存储每个元素后面第一个比它大的元素的下标。

在主函数中,首先读取数列的长度nn,然后读取数列的每个元素,存储在数组aa中。然后,对于数列中的每一个元素,检查栈顶元素是否小于当前元素。如果是,则更新栈顶元素在数组ff中的值为当前元素的下标,并弹出栈顶元素。然后将当前元素的下标入栈。这样,栈中的元素总是保持单调递减的顺序,即栈顶元素总是栈中最小的元素。

最后,输出数组ff中的每一个元素,即每个元素后面第一个比它大的元素的下标。

注意 :

  1. 因为要找的是第 ii 个元素之后第一个大于 aia_i 的元素的下标,所以要往栈里存下标而不是元素的数值。
  2. 可能会出现重复数据。因为要找的是第 ii 个元素之后第一个大于 aia_i 的元素的下标,所以当 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;
}