单调栈是一种下标单调、元素单调的栈
使用场景
若干区间内找最值,转化为枚举每个最值找区间
寻找每个元素\(a[i]\)向右(左)第一个比\(a[i]\)大(小)的位置
如何寻找\(a[i]\)右边第一个大于\(a[i]\)的位置?
- 枚举下标\(i\),\(a[i]\)与栈顶循环比较,若
a[i]>a[stk.top()]
,则R[stk.top()]=i,stk.pop()
- 下标\(i\)入栈
- 循环结束后,剩余在栈中的下标说明其右侧没有更大的元素
如何寻找\(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
- 由找区间最小值转化为指定\(a[i]\)为最小值找区间
- 若\(a[i]\)在区间\([L,R]\)内是最小值,那么在更小的区间内\(a[i]\)也能是最小值
- 大区间的答案可以直接向小区间做贡献
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;
}
标签:下标,int,top,pop,leq,区间,单调
From: https://www.cnblogs.com/wbw121124/p/17947629