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

【模板】单调栈

题目背景

模板题,无背景。

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

题目描述

给出项数为 n n n 的整数数列 a 1 … n a_{1 \dots n} a1n

定义函数 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<jn,aj>ai{j}。若不存在,则 f ( i ) = 0 f(i)=0 f(i)=0

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

输入格式

第一行一个正整数 n n n

第二行 n n n 个正整数 a 1 … n a_{1\dots n} a1n

输出格式

一行 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 n100

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

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 3 × 1 0 6 1 \le n\leq 3\times 10^6 1n3×106 1 ≤ a i ≤ 1 0 9 1\leq a_i\leq 10^9 1ai109


思路

首先,定义一个数组 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中的每一个元素,即每个元素后面第一个比它大的元素的下标。

注意 :

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

  • 25
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值