单调栈

单调栈是一种下标单调、元素单调的栈

使用场景

若干区间内找最值,转化为枚举每个最值找区间

寻找每个元素\(a[i]\)向右(左)第一个比\(a[i]\)大(小)的位置

如何寻找\(a[i]\)右边第一个大于\(a[i]\)的位置?

  1. 枚举下标\(i\)\(a[i]\)与栈顶循环比较,若a[i]>a[stk.top()],则R[stk.top()]=i,stk.pop()
  2. 下标\(i\)入栈
  3. 循环结束后,剩余在栈中的下标说明其右侧没有更大的元素

如何寻找\(a[i]\)左边第一个大于\(a[i]\)的位置?

倒序枚举,参照\(R[i]\)的处理方法即可。

洛谷P5788 【模板】单调栈

洛谷P2947 [USACO09MAR] Look Up S一样

题目描述

给出项数为 \(n\) 的整数数列 \(a_{1 \dots n}\)

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

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

输入格式

第一行一个正整数 \(n\)

第二行 \(n\) 个正整数 \(a_{1\dots n}\)

输出格式

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

样例 #1

样例输入 #1

5
1 4 2 3 5

样例输出 #1

2 5 4 5 0

提示

【数据规模与约定】

对于 \(30\%\) 的数据,\(n\leq 100\)

对于 \(60\%\) 的数据,\(n\leq 5 \times 10^3\)

对于 \(100\%\) 的数据,\(1 \le n\leq 3\times 10^6\)\(1\leq a_i\leq 10^9\)

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e6 + 5;
int n, a[N], b[N];
stack<int>q;
signed 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 (!q.empty() && a[i] > a[q.top()])
		{
			b[q.top()] = i;
			q.pop();
		}
		q.push(i);
	}
	for (int i = 1; i <= n; i++)
		cout << b[i] << ' ';
	return 0;
}

CF547B

  1. 由找区间最小值转化为指定\(a[i]\)为最小值找区间
  2. \(a[i]\)在区间\([L,R]\)内是最小值,那么在更小的区间内\(a[i]\)也能是最小值
  3. 大区间的答案可以直接向小区间做贡献

code

#include<bits/stdc++.h>
#define debug false
#define int long long
using namespace std;
const int N = 1e6 + 5;
int n, a[N], b[N], c[N], ans[N];
stack<int>q;
signed 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 (!q.empty() && a[i] < a[q.top()])
		{
			b[q.top()] = i;
			q.pop();
		}
		q.push(i);
	}
	while (!q.empty())
	{
		b[q.top()] = n + 1;
		q.pop();
	}
	for (int i = n; i >= 1; i--)
	{
		while (!q.empty() && a[i] < a[q.top()])
		{
			c[q.top()] = i;
			q.pop();
		}
		q.push(i);
	}
	for (int i = 1; i <= n; i++)
	{
		int len = (b[i] - 1) - (c[i] + 1) + 1;
		ans[len] = max(ans[len], a[i]);
	}
	for (int i = n; i >= 1; i--)
		ans[i] = max(ans[i], ans[i + 1]);
	for (int i = 1; i <= n; i++)
		cout << ans[i] << ' ';
	return 0;
}
posted @ 2024-01-05 16:54  wbw121124  阅读(36)  评论(0)    收藏  举报