首页 > 其他分享 >单调栈

单调栈

时间:2024-01-05 17:02:13浏览次数:22  
标签:下标 int top pop leq 区间 单调

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

使用场景

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

寻找每个元素\(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;
}

标签:下标,int,top,pop,leq,区间,单调
From: https://www.cnblogs.com/wbw121124/p/17947629

相关文章

  • 单调栈分类、封装和总结
    作者推荐map|动态规划|单调栈|LeetCode975:奇偶跳通过枚举最小(最大)值不重复、不遗漏枚举所有子数组C++算法:美丽塔O(n)解法单调栈左右寻找第一个小于maxHeight[i]的left,right,[left,right]直接的高度都是maxHeight[i]可以用封装的类,可以理解为枚举山顶这个子数组【单调栈]LeetCode8......
  • map|动态规划|单调栈|LeetCode975:奇偶跳
    作者推荐【贪心算法】【中位贪心】.执行操作使频率分数最大涉及知识点单调栈动态规划map题目给定一个整数数组A,你可以从某一起始索引出发,跳跃一定次数。在你跳跃的过程中,第1、3、5…次跳跃称为奇数跳跃,而第2、4、6…次跳跃称为偶数跳跃。你可以按以下方式从索引i向后跳转......
  • 浅谈单调栈
    单调栈,顾名思义,具有单调性的栈。单调,指满足一个序列是一个从小到大的序列或从大到小的序列。栈(\(stack\))是以一种线性存储结构,它具有以下特点:栈中的数据元素遵守“先进后出(\(First\in\Last\out\))”的原则,简称FILO结构;限定只能在栈顶进行插入和删除操作。所以,何为单......
  • 单调栈求解算法
    例题:503. 下一个更大元素II给定一个循环数组 nums ( nums[nums.length-1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一......
  • 【每日练习】将字符串翻转到单调递增、使字符串平衡的最少删除次数
    将字符串翻转到单调递增https://leetcode.cn/problems/flip-string-to-monotone-increasing/如果一个二进制字符串,是以一些0(可能没有0)后面跟着一些1(也可能没有1)的形式组成的,那么该字符串是单调递增的。给你一个二进制字符串s,你可以将任何0翻转为1或者将1翻转为0......
  • 浅谈单调栈
    单调栈,顾名思义,具有单调性的栈。单调,指满足一个序列是一个从小到大的序列或从大到小的序列。栈(\(stack\))是以一种线性存储结构,它具有以下特点:栈中的数据元素遵守“先进后出(\(First\in\Last\out\))”的原则,简称FILO结构;限定只能在栈顶进行插入和删除操作。所以,何为单......
  • 刷题 ST表、单调栈、线段树->区间最值
    2023.12.13cf1904D2解题思路首先,a[i]大于b[i]时肯定不行,等于就满足了,直接过掉其次,要想使得a[i]等于b[i],就要在a[i]左右找最近的j使得a[j]=b[i](最近的最优,可证)k是i和j中间的一个数,想要满足题意,要满足以下两个条件(a[j]=b[i])1.ak<aj,即max(区间[i,j]中的ak)2.bk>bi,即min(区间......
  • 单调栈与单调队列算法总结
    单调栈知识概览单调栈最常见的应用是找到每一个数离它最近的且比它小的数。单调栈考虑的方式和双指针类似,都是先想一下暴力做法是什么,然后再挖掘一些性质如单调性,最终可以把目光集中在比较少的状态中,从而达到降低时间复杂度的作用,都是算法优化的一种手段。对于的情况,更有可能......
  • 单调队列
    一、算法描述本篇文章讲述的数据结构是单调队列,主要用于解决滑动窗口类问题的数据结构,即,在长度为\(n\)的序列中,求每个长度为\(m\)的区间的区间最值,时间复杂度\(O(n)\)。思路如下:用一个队列\(q[N]\)来存储可能是答案的下标。先判断是否滑出了窗口,如果滑出了则删除......
  • 单调栈
    一、算法描述本篇文章讲述的数据结构是单调栈,是一种和单调队列类似的数据结构(下一篇文章会讲到)。单调队列主要用于\(O(n)\)解决滑动窗口问题,单调栈主要用于\(O(n)\)解决NGE问题(NextGreaterElement),也就是对序列中的每个元素,找到上(下)一个比它大(小)的元素,原理相同。以下面......