单调队列

单调队列以及单调队列优化DP

こ雲淡風輕ζ 提交于 2019-11-27 18:10:58
单调队列定义:    其实单调队列就是一种队列内的元素有单调性的队列,因为其单调性所以经常会被用来维护区间最值或者降低DP的维数已达到降维来减少空间及时间的目的。   单调队列的一般应用:     1.维护区间最值     2.优化DP 例题引入:   求m区间内的最小值: https://www.luogu.org/problemnew/show/P1440    一个含有n项的数列(n<=2000000),求出每一项前的m个数到它这个区间内的最小值。若前面的数不足m项则从第1个数开始,若前面没有数则输出0。 例题解答:     首先看到题目可以很快想到O(NM),对于2*10^6这样的数据无疑要TLE的;    接下来考虑用单调队列,因为每一个答案只与当前下标的前m个有关,所以可以用单调队列维护前m的个最小值,    考虑如何实现该维护的过程??    显然当前下标X的m个以前的元素(即下标小于X-M+1的元素)肯定对答案没有贡献,所以可以将其从单调队列中删除。    对于两个元素A,B,下标分别为a,b,如果有A>=B&&a<b那么B留在队列里肯定优于A,因此可以将A删除。    维护队首:如果队首已经是当前元素的m个之前,将head++,弹出队首元素    维护队尾:比较q[tail]与当前元素的大小,若当前元素更优tail++,弹出队尾元素

单调队列

最后都变了- 提交于 2019-11-27 16:49:22
单调队列,顾名思义,就是一个元素具有单调性的队列,{1,2,5}这是一个单调增的队列,{6,4,1}这是一个单调减的队列。 其用途我们通过一道例题来说明 洛谷P1866 滑动窗口 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。 例如 题意是有一个长度为N的序列,还有一个长度为k的区间,区间每次向右滑动一位,求每次滑动过后的最大值和最小值。 这道题可以用线段树或ST表来解决,这里仅仅说单调队列。 如果我们维护一个队列,保持队首是要查找的值,那么每次滑动的时候,我们输出队首即可。 现在问题是,我们怎么样维护这样一个合法的队首,我们就应用了单调队列。 这里以最大值为例,试想,如果碰到一个新的元素num[j](i<j),如果num[i]>num[j],那么num[i]和num[j]都是有用的, 因为如果窗口往后滑, num[i]滑出了区间,弹出队列,那么num[j]可能会成为那个合法的队首,所以num[i]和num[j], 我们都要记下来,再如果num[i]<=num[j](i<j),那么num[i]永远也不会成为将要查询区间的合法元素,所以直接弹掉 即可,明确了这一点剩下只是一些简单的操作。 在队列中记下每个元素在原序列中的位置,如果这个元素不在查询序列中了就弹掉。 如果碰到 num

[树形dp][Tarjan][单调队列] Bzoj 1023 cactus仙人掌图

岁酱吖の 提交于 2019-11-27 14:59:35
Description   如果某个无向连通图的任意一条边至多只出现在一条简单回路(simple cycle)里,我们就称这张图为仙人掌 图(cactus)。所谓简单回路就是指在图上不重复经过任何一个顶点的回路。   举例来说,上面的第一个例子是一张仙人图,而第二个不是——注意到它有三条简单回路:(4,3,2,1,6 ,5,4)、(7,8,9,10,2,3,7)以及(4,3,7,8,9,10,2,1,6,5,4),而(2,3)同时出现在前两 个的简单回路里。另外,第三张图也不是仙人图,因为它并不是连通图。显然,仙人图上的每条边,或者是这张仙 人图的桥(bridge),或者在且仅在一个简单回路里,两者必居其一。定义在图上两点之间的距离为这两点之间最 短路径的距离。定义一个图的直径为这张图相距最远的两个点的距离。现在我们假定仙人图的每条边的权值都是1 ,你的任务是求出给定的仙人图的直径。 题解 如果是圆圆边的话和普通的树形dp一样 对于环的话,把他拎出来单独考虑,首先要计算出这个环的贡献,然后更新环的最顶点 更新的话,就这个直接拿环上的点的dp值 ,再计算一下这两点之间的最短路 ,相加后更新 贡献的话,就是max(f[i]+f[j]+dis(i,j)),dis(i,j)=min(abs(deep[i]-deep[j]),size[环]-abs(deep[i]-deep[j]))

滑动窗口-洛谷T1866(单调队列)

久未见 提交于 2019-11-27 09:23:36
咕咕咕 单调队列板子题 一、基本 1.单调队列: 特殊的双端队列,内部元素。分为最大队列(单调递增)和最小队列(单调递减)两种 二、应用 本题中:大部分单调队列优化的动态规划问题都和定长连续子区间的最值问题 #include<bits/stdc++.h> using namespace std; inline int read() { int sum = 0,p = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') p = -1; ch = getchar(); } while(ch >= '0' && ch <= '9') { (sum *= 10) += ch - '0'; ch = getchar(); } return sum * p; } const int N = 1e6 + 5; int n,k,head,tail; int a[N],fn[N],fx[N],num[N],q[N]; void dpmin() { head = 1,tail = 0; for(int i = 1;i <= n;i++) { while(num[head] < i - k + 1 && head <= tail) head++; while(a[i] <= q[tail] && head <= tail

单调队列优化多重背包 洛谷P1776 宝物筛选

泄露秘密 提交于 2019-11-27 07:12:21
题目链接: https://www.luogu.org/problem/P1776 单调队列,就是在区间移动时动态维护区间的最值 看了蛮久还是蛮晕的,看不太明白,因为单调队列和多重背包都很不熟,不想继续在这个知识点上浪费时间了,就先记住模板吧,之后题做多了,写题时遇到了,多多温习。 看的几篇博客: https://blog.csdn.net/qq_40679299/article/details/81978770 https://www.cnblogs.com/-guz/p/9866118.html #include <bits/stdc++.h> using namespace std; typedef long long ll; const int mod=1e9+7; const int inf=1<<30; const int maxn=4e4+7; int dp[maxn],q[maxn],p[maxn]; int main(){ int n,W;cin>>n>>W; int ans=0; for(int i=1;i<=n;i++){ int v,w,num;scanf("%d%d%d",&v,&w,&num); if(w==0)ans+=v*num; num=min(W/w,num);//最大能够承载的该物品的数量 for(int d=0;d<w;d++){/

单调队列优化多重背包 洛谷P1776 宝物筛选

删除回忆录丶 提交于 2019-11-27 06:41:01
题目链接: https://www.luogu.org/problem/P1776 首先我们知道单调队列,就是在区间移动时动态维护区间的最值 单调队列优化的主要思想就是分组更新,因为w[i] w[i]w[i]是成倍增加的 对于当前为w的体积,我们可以按它的余数分w组,即0,1....w-1 同一个余数的在一组 每组的转移是不影响的,也就是说单独转移 f [ i ] [ 5 w ] = m a x ( f [ i − 1 ] [ 4 w ] − 4 v , f [ i − 1 ] [ 3 w ] − 3 v , f [ i − 1 ] [ 2 w ] − 2 v , f [ i − 1 ] [ w ] − v , f [ i − 1 ] [ 0 ] ) f [ i ] [ 4 w ] = m a x ( f [ i − 1 ] [ 3 w ] − 3 v , f [ i − 1 ] [ 2 w ] − 2 v , f [ i − 1 ] [ w ] − v , f [ i − 1 ] [ 0 ] ) 如上所示,每一个都可能有其组内前几个更新来,且不确定是哪个更新的,所以就可以用单调队列优化啦,维护区间的最大值。区间长度就是物品的个数num 原来的状态转移方程为: f [ i ] [ j ] = m a x ( f [ i − 1 ] [ j ] , f [ i − 1 ] [ j −

[洛谷]P1714 切蛋糕 (#单调队列)

馋奶兔 提交于 2019-11-27 05:55:56
题目描述 今天是小Z的生日,同学们为他带来了一块蛋糕。这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每小块都有对应的幸运值。 小Z作为寿星,自然希望吃到的第一块蛋糕的幸运值总和最大,但小Z最多又只能吃M小块(M≤N)的蛋糕。 吃东西自然就不想思考了,于是小Z把这个任务扔给了学OI的你,请你帮他从这N小块中找出连续的k块蛋糕(k≤M),使得其上的幸运值最大。 输入格式 输入文件cake.in的第一行是两个整数N,M。分别代表共有N小块蛋糕,小Z最多只能吃M小块。 第二行用空格隔开的N个整数,第i个整数Pi代表第i小块蛋糕的幸运值。 输出格式 输出文件cake.out只有一行,一个整数,为小Z能够得到的最大幸运值。 输入输出样例 输入 #1 复制 5 2 1 2 3 4 5 输出 #1 复制 9 输入 #2 复制 6 3 1 -2 3 -4 5 -6 输出 #2 复制 5 说明/提示 对20%的数据,N≤100。 对100%的数据,N≤500000,|Pi|≤500。 答案保证在2^31-1之内。 思路 n个数中取连续的k(k<=m)个数,输出其中所有可能的最大值。 #include <stdio.h> #include <iostream> #include <deque> #define linf -2e9-7 using namespace std; int n,m,s

2019 牛客暑期多校 第八场 A All-one Matrices (单调栈+前缀和)

余生颓废 提交于 2019-11-27 00:35:18
学习内容 :单调队列 单调栈的各种用途 今日完成题数 :4 多校补题情况(之前定的每支队伍标准) :√ 今日看书情况 :2 学习算法的总结 矩阵类题,如果是求个数和某某最大一般都是如下的两种情况 再次套用 付队 说的话 1,我们可以枚举上下边界,把矩阵转化为一维来做,复杂度n^3,例子,最大子矩阵之和,最大矩阵最大最小值差值<=m, 2,我们可以枚举下边界,以这个下边界当作高楼的底,然后用单调栈进行操作,求一个矩阵 今日做题总结 HihoCoder - 1664 (单调队列) HihoCoder - 1673 (单调队列) 2019 牛客暑期多校 第三场 F Planting Trees (单调队列+尺取) 2019 牛客暑期多校 第八场 A All-one Matrices (单调栈+前缀和) 心得: 今天虽然前两个都用了至少三个小时在找写和找bug,但是感觉收获颇丰,现在觉得遇到这种矩阵类型的题绝对立马斩下,所以深入理解原理还是很重要 来源: https://www.cnblogs.com/Lis-/p/11336714.html

单调队列 洛谷P1886 滑动窗口

安稳与你 提交于 2019-11-27 00:11:09
题目链接: https://www.luogu.org/problem/P1886 题意:给一串一维数字序列,并给你一个长为k的小框,从左到右一格格滑过去,求每次小框内的最大值最小值分别为多少。 据说是单调队列模板题。讲解洛谷排第一的题解就讲的很好。 简略说就是维护一个单调的队列(增或减)每次移到新的一格就会把队尾和当前做比较,不满足单调性就一直去掉队尾,一直到满足为止,因为有单调性,队首就是答案。除了队列q数组,还有一个p数组,用来放队内元素在原序列中的下标。 #include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf=1<<30; const int maxn=1e6+7; int a[maxn],p[maxn],q[maxn]; int n,k; void ask_min(){ memset(p,0,sizeof(p)); memset(q,0,sizeof(q)); int tail=1,head=0; for(int i=1;i<=n;i++){ while(head<=tail&&q[tail]>=a[i])tail--; q[++tail]=a[i];p[tail]=i; while(p[head]<=i-k)head++; if(i>=k)printf("%d "

[单调队列]烽火传递

风格不统一 提交于 2019-11-27 00:09:43
Description   烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情,在某两座城市之间有 n 个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续 m 个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递。    Input   第一行:两个整数 N,M。其中N表示烽火台的个数, M 表示在连续 m 个烽火台中至少要有一个发出信号。接下来 N 行,每行一个数 Wi,表示第i个烽火台发出信号所需代价。 Output   一行,表示答案。 Sample Input 5 3 1 2 5 6 2 Sample Output 4 Data Constraint 对于50%的数据,M≤N≤1,000 。 对于100%的数据,M≤N≤100,000,Wi≤100。 思路:定义状态dp[i]表示,点燃第i个烽火台并保持第1~i个烽火台满足题意(每m个中至少一个被点燃),的最小花费是多少;状态转移方程:dp[i]=min{dp[j]}(i-m=<j<=i-1)+w[i];则求出dp[1~n]的复杂度是O(n^2),会炸;于是,可以维护一个单调递增队列,在求min{dp[j]}(i-m=<j<=i-1)时不用枚举,只需O(1