洛谷 - P1886 滑动窗口(单调队列/线段树)
题目链接:点击查看
题目大意:给出一个由n个数构成的序列,再给出一个长度为k的窗口,这个窗口从第一个下标开始一直向后移动,每次移动一个单位,每次移动询问一次该窗口中的最大值和最小值,最后输出答案
题目分析:看似是一个模拟,其实暴力模拟肯定会爆,因为涉及到区间最值问题,而且还是静态的询问,所以这个题目有三种方法可以解决,分别是st表,线段树和单调队列,因为st表我不会优化,所以有五个测试点MLE了,这里就不用那个方法了,线段树的话空间复杂度比起st表一般是能小上5倍左右,但时间复杂度每一次查询时要多logn的常数,所以酌情考虑吧,用线段树的话就不会MLE了,擦边把这个题目给A了,一会也放一下代码,没什么好说的,主要是来说一下单调队列来做这个题目,之前只是学过单调栈,今天接触了一下单调队列,发现还是挺简单的,主要原理就是用双端队列维护一个严格递增或严格递减的序列,每次增加一个新值的时候,将其与尾部比较,最终插入尾部,当使用的时候,是使用头部的数值,大概就是这样了,一会看代码理解一下吧
然后这个题目还需要维护一下每个数值所代表的id,用来判断该数值在当前区间中是否过期,若过期的话直接舍弃掉即可
当然三种方法的复杂度来比较一下吧:
st表:空间复杂度nlogn,时间复杂度:打表nlogn,查询O(1)
线段树:空间复杂度n*4,时间复杂度:建树nlogn,查询nlogn
单调队列:空间复杂度n,时间复杂度:n
吐槽一句:这个题目本来是poj上的题目,为什么跑来洛谷做呢,三种方法,st表MLE,线段树TLE,单调队列还不支持C++11,我:????
代码:
单调队列(deque):
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<deque>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e6+100;struct Node
{int val,id;
}a[N];int ans_max[N],ans_min[N];int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);int n,k;while(scanf("%d%d",&n,&k)!=EOF){for(int i=1;i<=n;i++){scanf("%d",&a[i].val);a[i].id=i;}deque<Node>mmax;//维护最大值的单调队列deque<Node>mmin;//维护最小值的单调队列for(int i=1;i<=k-1;i++)//预处理1~k-1的值{while(mmax.size()&&mmax.back().val<=a[i].val)//将比当前值小的数全删掉(尾部)mmax.pop_back();mmax.push_back(a[i]);while(mmin.size()&&mmin.back().val>=a[i].val)//将比当前值大的数全删掉(尾部)mmin.pop_back();mmin.push_back(a[i]);}for(int i=k;i<=n;i++)//枚举滑动窗口的末尾位置{int left=i-k+1;//记录滑动窗口的首位置while(mmax.size()&&mmax.back().val<=a[i].val)//将比当前值小的数全删掉(尾部)mmax.pop_back();mmax.push_back(a[i]);while(mmin.size()&&mmin.back().val>=a[i].val)//将比当前值大的数全删掉(尾部)mmin.pop_back();mmin.push_back(a[i]);while(mmax.size()&&mmax.front().id<left)//将过期的值删掉(头部)mmax.pop_front();while(mmin.size()&&mmin.front().id<left)//将过期的值删掉(头部)mmin.pop_front();ans_max[left]=mmax.front().val;//更新答案ans_min[left]=mmin.front().val;}printf("%d",ans_min[1]);for(int i=2;i+k-1<=n;i++)printf(" %d",ans_min[i]);printf("\n%d",ans_max[1]);for(int i=2;i+k-1<=n;i++)printf(" %d",ans_max[i]);printf("\n");}return 0;
}
单调队列(模拟):专门给poj2823改的代码
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e6+100;struct Node
{int val,id;
}t[N];int a[N];int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);int n,k;while(scanf("%d%d",&n,&k)!=EOF){for(int i=1;i<=n;i++)scanf("%d",a+i);int l=1,r=0;for(int i=1;i<=n;i++){int left=i-k+1;while(l<=r&&t[l].id<left)l++;while(l<=r&&t[r].val>=a[i])r--;t[++r].val=a[i];t[r].id=i;if(i>=k)printf("%d ",t[l].val);}printf("\n");l=1,r=0;for(int i=1;i<=n;i++){int left=i-k+1;while(l<=r&&t[l].id<left)l++;while(l<=r&&t[r].val<=a[i])r--;t[++r].val=a[i];t[r].id=i;if(i>=k)printf("%d ",t[l].val);}printf("\n");}return 0;
}
线段树:
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=1e6+100;int ans1[N],ans2[N];struct Node
{int l,r,mmax,mmin;
}tree[N<<2];void build(int k,int l,int r)
{tree[k].l=l;tree[k].r=r;if(l==r){scanf("%d",&tree[k].mmin);tree[k].mmax=tree[k].mmin;return;}int mid=l+r>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);tree[k].mmax=max(tree[k<<1].mmax,tree[k<<1|1].mmax);tree[k].mmin=min(tree[k<<1].mmin,tree[k<<1|1].mmin);
}int query_max(int k,int l,int r)
{if(tree[k].r<l||tree[k].l>r)return -inf;if(tree[k].r<=r&&tree[k].l>=l)return tree[k].mmax;return max(query_max(k<<1,l,r),query_max(k<<1|1,l,r));
}int query_min(int k,int l,int r)
{if(tree[k].r<l||tree[k].l>r)return inf;if(tree[k].r<=r&&tree[k].l>=l)return tree[k].mmin;return min(query_min(k<<1,l,r),query_min(k<<1|1,l,r));
}int main()
{
// freopen("input.txt","r",stdin);
// ios::sync_with_stdio(false);int n,k;while(scanf("%d%d",&n,&k)!=EOF){build(1,1,n);for(int i=1;i+k-1<=n;i++){ans1[i]=query_min(1,i,i+k-1);ans2[i]=query_max(1,i,i+k-1);}printf("%d",ans1[1]);for(int i=2;i+k-1<=n;i++)printf(" %d",ans1[i]);printf("\n%d",ans2[1]);for(int i=2;i+k-1<=n;i++)printf(" %d",ans2[i]);printf("\n");}return 0;
}
洛谷 - P1886 滑动窗口(单调队列/线段树)相关推荐
- 洛谷 P1886 滑动窗口
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- 入门经典_Chap08_题解总结:极角扫描法 滑动窗口 单调队列 单调栈
总结 本章主要关注一个重要的问题 – 单调队列和单调栈的使用 同时还有一些其他的问题,如扫描法,递归的思想, 构造, 分治, 二分等 知识点 单调队列 和 单调栈 题目 UVA - 1606 Am ...
- 【洛谷 P1638】 【单调队列】 逛画展
[洛谷 P1638] [单调队列] 逛画展 题目 解题思路 先求出最前面囊括所有画的位置 然后如果左边界的画不止存在一次,左边界右移 不断扩展右边界,求取答案 代码 #include<iostr ...
- [USACO18JAN]Lifeguards P 洛谷黑题,单调队列优化DP
传送门:戳我 这道题有两个版本,S和P,S是K等于1的情况,显然可以用线段树水过. P版本就难了很多,洛谷黑题(NOI/NOI+/CTSC),嘿嘿. 我自己也不是很理解,照着题解写了一遍,然后悟到了一 ...
- 滑动窗口--单调队列
给定一个大小为 n≤106 的数组. 有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边. 你只能在窗口中看到 k 个数字. 每次滑动窗口向右移动一个位置. 以下是一个例子: 该数组为 [1 ...
- 力扣1438——绝对差不超过限制的最长连续子数组(滑动窗口+单调队列)
题目描述(中等) 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit . 如果不存在满足条件 ...
- POJ2823 滑动窗口 单调队列模板题 第一次用了发函数指针
题意 有一个n长的序列,用k长的窗口在上面滑动,去每次窗口中最小和最大的数. 思路 使用单调队列,维护这个队列是单调的.以取最小元素为例,若窗口内左边元素>=右边元素,则左边元素失去保留的意义, ...
- 【洛谷】【动态规划+单调队列】P1725 琪露诺
[题目描述:] 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精. 某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来.但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸.于是琪露诺决定到河 ...
- 洛谷 - P1714 切蛋糕(单调队列+前缀和+思维)
题目链接:点击查看 题目大意:给出一个由n个数组成的序列,求长度不超过m的连续子段和中的最大值 题目分析:因为给出了一个限制条件,所以这就不能当普通的动态规划来做了,我们可以跑一遍前缀和,然后枚举每一 ...
最新文章
- mysql 中模糊查询的四种用法介绍
- 树莓派:3安装NodeJS
- ruby中的self
- dp之二维背包poj1837(天平问题 推荐)
- 选redis还是memcache,源码怎么说?
- python查找excel中字符串_在Python问题中通过Excel搜索字符串/正则表达式
- oracle服务器支持ipmi带外管理,ipmi带外管理
- 【ML】理解偏差和方差,过拟合和欠拟合
- php和app关系,php在app开发中的应用
- C语言程序100例之C#版-019
- 印尼Widya Robotics携手华为云,让建筑工地安全看得见
- mac adb环境变量配置
- 读《如何找对另一半》后感以及论自己择偶标准
- python 等差数列_413. 等差数列划分(Python)
- Android Studio导入第三方sdk
- 机器视觉运动控制一体机应用例程|锂电池组装线上的读码应用
- python学了没有用_如何用Python进行无监督学习
- md文件打开错误(Failed to load file)
- send/sendto和recv/recvfrom各自的区别
- LabVIEW控制Arduino实现示波器(基础篇—7)