单调队列

单调队列

大憨熊 提交于 2020-02-05 00:54:40
题目 代码如下: # include <iostream> using namespace std ; const int N = 1000010 ; int a [ N ] , q [ N ] ; int main ( ) { int hh = 0 , tt = - 1 ; int n , k ; cin >> n >> k ; for ( int i = 0 ; i < n ; i ++ ) cin >> a [ i ] ; for ( int i = 0 ; i < n ; i ++ ) { if ( hh <= tt && i - k + 1 > q [ hh ] ) hh ++ ; //判断队首是否已退队 while ( hh <= tt && a [ i ] <= a [ q [ tt ] ] ) tt -- ; q [ ++ tt ] = i ; if ( i >= k - 1 ) cout << a [ q [ hh ] ] << ' ' ; } puts ( "" ) ; //输出换行 hh = 0 , tt = - 1 ; //别忘了重新声明hh和tt for ( int i = 0 ; i < n ; i ++ ) { if ( hh <= tt && i - k + 1 > q [ hh ] ) hh ++ ; while ( hh <= tt && a [

单调队列、单调栈、优先队列模板

偶尔善良 提交于 2020-02-03 00:02:24
目录 单调栈、单调队列及优先队列 1.单调队列 2.单调栈 3.优先队列 单调栈、单调队列及优先队列 1.单调队列 单调队列的描述:指队列中元素之间关系具有单调性,而且队首和队尾都可以出队,但是只有队尾可以进行入队操作。 其重要作用是找到前n个后者后n个数的最值。 其具体操作是:假设单调队列是单调递减队列,假设在插入元素v时,将队列尾部的元素同v比较,如果队列尾部的元素不大于元素v,我们直接删除队尾元素,再将队尾元素与v比较,直至队尾元素比v大,这个时候我们将v插入队尾。其实现代码如下: int que[100]; int head = 0, tail = 0; void push(int a) //进队 { que[++tail] = a; } int pop() //出队 { return que[++head]; } bool empty() //判断队列是否为空 { return !(head < tail); } 下面是求一个整数序列中每k个中的最大值和最小值的代码: #include<iostream> #include<cstdio> using namespace std; const int maxn=1e6+10; int arr[maxn],que[maxn]; int main() { int n,k; scanf("%d%d",&n,&k); for

环路运输 (单调队列)

…衆ロ難τιáo~ 提交于 2020-02-01 02:02:49
题目描述 在一条环形公路旁均匀地分布着N座仓库,编号为1~N,编号为 i 的仓库与编号为 j 的仓库之间的距离定义为 dist(i,j)=min⁡(|i-j|,N-|i-j|),也就是逆时针或顺时针从 i 到 j 中较近的一种。每座仓库都存有货物,其中编号为 i 的仓库库存量为 Ai。在 i 和 j 两座仓库之间运送货物需要的代价为 Ai+Aj+dist(i,j)。求在哪两座仓库之间运送货物需要的代价最大。1≤N≤10^6,1<=Ai<=10^7。 输入 第一行一个整数N,第二行N个整数A1~AN。 输出 一个整数,表示最大代价。 样例输入 复制样例数据 5 1 8 6 2 5 样例输出 15 但是因为最大子序和的时候是不是单调队列做的,所以还是当作再熟悉一下单调队列思路很清晰,将环断开变成二倍长,枚举每个位置i,求i-n/2<=j<=i-1的区间范围内a[j]-j的最大值maxx这个就需要单调队列维护一下,然后每个对于每个i最大值就是i+a[i]-(maxx)最后比较一下即可我们需要维护一个单调递减的队列,因为对于位置靠前但是值更小的值是没意义的,所以每次进入值时这个值一定要是队列里面的最小值 #include "bits/stdc++.h" using namespace std; const int maxn=2e6+10; typedef long long ll; int

浅谈单调队列解决滑动窗口问题

旧街凉风 提交于 2020-01-31 04:17:14
这次我们了解一下 滑动窗口 的问题 作者ID:qq_43341171 首先,让我们了解一下 滑动窗口 是什么? 这里有一张图(来自POJ),解释了滑动窗口的意思: 我们可以看见,一个长度固定为3的框(窗口)从左端点移动到右端点,每次移动一个数,这就是我们所说的“ 滑动窗口 ”。 而 每次滑动窗口的最大值以及最小值 就指的是滑动窗口在每次移动后区间内的最大值以及最小值。 例如:上图当中,第一次移动后(第一排),窗口区间包含了:“1,3,-1”。那么滑动窗口的长度为3(有3个数),在这3个数当中,最大值为3,最小值为-1,所以这个滑动窗口的最大值为3,最小值为-1。 了解了滑动窗口,让我们再来了解一下 单调队列 单调队列,即单调递减或单调递增的队列。 但是,这个说法很笼统,到底什么是单调队列呢? 这里有张我做的图: 从这张图里,我们能看出: 单调递增队列(从队首到队尾递增)的维护方法: 入队一个数,就把它前面所有比它大的数给弹掉 准确地说 ,是把前面所有比它大的数给弹掉 再入队 单调递减队列(从队首到队尾递减)的维护方法: 入队一个数,就把它前面所有比它小的数给弹掉 准确地说 ,是把前面所有比它小的数给弹掉 再入队 但是问题来了:单调队列是如何把后面的数给弹掉的呢?(我们众所周知,队列只能在队首弹出) 答案(敲黑板):其实单调队列的两端都可以弹出!!! 那么这样,单调队列的问题就解决啦

单调栈与单调队列

徘徊边缘 提交于 2020-01-31 00:52:48
版权声明:本文为CSDN博主「Alex_McAvoy」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/u011815404/article/details/86896303 目录 【单调栈】 1.原理 2.应用 3.实现 1)单调递增栈 2)单调递减栈 【单调队列】 1.原理 2.应用 3.实现 1)单调递增队列 2)单调递减队列 【单调栈】 1.原理 单调栈,就是栈内元素保持一定单调性(单调递增或单调递减)的栈,即从栈底到栈顶单调递增或递减。 对于单调递增的栈,如果栈为空或入栈元素值大于等于栈顶元素值,则入栈;否则,若入栈会破坏栈的单调性,因此需要将比入栈元素大的元素全部出栈。 对于单调递减的栈,如果栈为空或入栈元素值小于等于栈顶元素值,则入栈;否则,若入栈会破坏栈的单调性,因此需要将比入栈元素小的元素全部出栈。 2.应用 单调栈常用的应用有: 给定一组数,对于某个数,找到从左/右遍历第一个比它小/大的元素的位置 给定一组数,针对每个数,寻找其与其左/右第一个比它小/大的数之间有多少个数 给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列的长度最大 给定一序列,寻找某一子序列,使得子序列中的最小值乘以子序列所有元素和最大 3.实现 1)单调递增栈 stack < int > S

单调队列原理+练习

时光怂恿深爱的人放手 提交于 2020-01-30 21:55:34
很早之前就学过了,现在系统的再学习下,做个汇总。 原理 deque实现,队头存最大值/最小值,从队头到队尾使之单调减/增。 以队头存最小值为例: 队列为空,直接入队 依次将队列中大于(等于也可以)当前值的数从队尾出队,最后再将当前值入队尾 deque < int > q ; for ( int i = 0 ; i < n ; i ++ ) { while ( ! q . empty ( ) && q . back ( ) > a [ i ] ) q . pop_back ( ) ; q . push_back ( a [ i ] ) ; } 练习 洛谷P1886-滑动窗口-模版题 传送门 解题思路: 因为有长度k的限制,所以队列中存的是值的下标。在输出结果时要保证队头的元素在[i-k+1,i]内,即将队列中不再该范围内的值依次从队头取出,再输出当前的最大/小值。 ac代码: # include <bits/stdc++.h> typedef long long ll ; using namespace std ; const int maxn = 1e6 + 10 ; int a [ maxn ] ; deque < int > q ; //队头最大/小值 int n , k ; int main ( ) { //freopen("/Users/zhangkanqi/Desktop

AcWing 154. 滑动窗口 单调队列

瘦欲@ 提交于 2019-12-25 20:20:12
地址 https://www.acwing.com/problem/content/description/156/ 输入格式 输入包含两行。 第一行包含两个整数n和k,分别代表数组长度和滑动窗口的长度。 第二行有n个整数,代表数组的具体数值。 同行数据之间用空格隔开。 输出格式 输出包含两个。 第一行输出,从左至右,每个位置滑动窗口中的最小值。 第二行输出,从左至右,每个位置滑动窗口中的最大值。 输入样例: 8 3 1 3 -1 -3 5 3 6 7 输出样例: -1 -3 -3 -3 3 3 3 3 5 5 6 7 算法1 单调队列 求最大值和最小值的过程其实是一样的 就是求极值的过程 以求最小值为例 我们使用一个队列来进行记录 处于滑动窗口的m个数字 以插入的数据的角度来看 如果插入的数据比之前的m-1个数字都小 那么它就将清空之前的m-1个数字成为队首 如果插入的数据比之前m-1个数字中的某一个数字较大 那么它在该数字退出队列后 还是有可能成为最小数值的,也需要保留该插入数字,只不过插入的数字不是队首(以后有可能成为队首) 这个队里有三个性质 1 队首是最小数(以求最小值为例) 2 队列中队首和队尾数字的索引差值最大为m,也就是控制数值在滑动窗口范围内 3 队列中前部的数字如果比后面的数字大,那么在m个的滑动窗口中,它是不可能成为最小值(队首)的,需要排除出队列

单调栈与单调队列

▼魔方 西西 提交于 2019-12-25 15:42:31
单调栈 特点 栈内的元素单调递增或者单调递减,可以求出数列中所有数的左边或右边第一个比其大或小的元素,总时间复杂度为 \(O(n)\) 例子 单调栈中一般存索引 如何实现呢? 以单调递增栈求需入栈元素X的两边第一个比X小的值为例,每次有元素a[i] = X进栈时, // a[i] = X while (栈不为空 且 栈顶元素s[top] >= a[i]) 栈顶元素出栈 // 直到栈顶元素s[top] < X或者栈为空 // X入栈 s.push(a[i]) 当栈顶元素比a[i]大时,对于未来的a[i+1], a[i+2],...来说,比a[i]更大的栈顶元素与a[i]相比,选择a[i]始终更优 以4,2,3为例,最开始4入栈, 当需要2入栈时,由于2比4小,对于2之后的元素3来说,其左边第一个数选择了2一定不会选择4,2始终比4更优 回到正题,根据单调递增栈的特性可以得出 当X入栈时(对应 s.push(a[i]) ),此时栈顶索引元素所指的值就是X左边第一个比X小的值, 栈为空则没有 当栈顶出栈时(对应 while ),此时的X为右边第一个比栈顶元素小的值 例题 84. Largest Rectangle in Histogram class Solution { public: int largestRectangleArea(vector<int>& heights) {

POJ 2823 Sliding Window + 单调队列

假如想象 提交于 2019-12-24 04:07:13
一、 概念介绍 1、 双端队列 双端队列是一种线性表,是一种特殊的队列,遵守先进先出的原则。双端队列支持以下4种操作: (1) 从队首删除 (2) 从队尾删除 (3) 从队尾插入 (4) 查询线性表中任意一元素的值 2、 单调队列 单调队列是一种特殊的双端队列,其内部元素具有单调性。最大队列与最小队列是两种比较常用的单调队列,其内部元素分别是严格单调递减(不是非递增)和严格单调递增(不是非递减)的。 单调队列的常用操作如下: (1) 插入:若新元素从队尾插入后会破坏单调性,则删除队尾元素,直到插入后不再破坏单调性为止,再将其插入单调队列。 (2) 获取最优(最大、最小)值:访问队首元素 以下是一个单调递增队列的例子: 队列大小不能超过3,入队元素依次为3,2,8,4,5,7,6,4 3入队:(3) 3从队尾出队,2入队:(2) 8入队:(2,8) 8从队尾出队,4入队:(2,4) 5入队:(2,4,5) 2从队头出队,7入队:(4,5,7) 7从队尾出队,6入队:(4,5,6) 6从队尾出队,5从队尾出队,4从队尾出队,4入队:(4) 以上左端为队头,右端为队尾。 二、 单调队列的应用 1、最大值的维护: 比如我们要维护一个区间为k的最大值的单调队列,由于新插入 的节点他的“生命力”肯定比原先已经在队列中的元素“活”的时间长,将插入元素不断与队尾元素比, 如果他大于队尾元素

单调队列优化多重背包

别说谁变了你拦得住时间么 提交于 2019-12-20 20:30:02
http://codevs.cn/problem/5429 / 把背包体积按 模物品体积 分类 在每个剩余类中使用单调队列 具体点就是 设物品体积为v,价值为w,现在要计算体积模v=0时的价值 设f[i][j] 表示 前i个物品,体积为j时的最大价值 f[i][5v]=max{ f[i-1][4v]+w , f[i-1][3v]+2w , f[i-1][2v]+3w , f[i-1][v]+4w , f[i-1][0]+5w } f[i][4v]=max{ f[i-1][3v]+w , f[i-1][2v]+2w , f[i-1][v]+3w , f[i-1][0]+4w } 对所有的f[i][j]-j/v*w f[i][5v]=max{ f[i-1][4v]-4w , f[i-1][3v]-3w , f[i-1][2v]-2w , f[i-1][v]-w , f[i-1][0] } f[i][4v]=max{ f[i-1][3v]-3w , f[i-1][2v]-2w , f[i-1][v]-w , f[i-1][0] } 即 f[i][j]=max{f[i-1][j%v+k*v]-k*w}+j*w 当固定了j%v后,就可以使用单调队列优化了 #include<cstdio> using namespace std; int dp[7001]; int q[7001][2];