[洛谷P1886]滑动窗口 (单调队列)(线段树)
---恢复内容开始---
这是很好的一道题
题目描述:
现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口。
现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
例如:
队列 [1 3 -1 -3 5 3 6 7]
窗口大小为3.
则如下图所示:
输入输出格式:
输入格式:
输入一共有两行,第一行为n,k。
第二行为n个数(<INT_MAX).
输出格式:
输出共两行,第一行为每次窗口滑动的最小值
输入样例:
- - -
输出样例:
- - - - -
解决方案:
(一)st表
(二)线段树
这里用到了两个结构体,然后就是进行普通的线段树求最大最小,这里就不再赘述了q
第一个结构体是查询用的
第二个结构体就是线段树了,这里我用了一个构造函数;
其实这些操作只是为了加速我们的线段树过程(让它别T)
不过总体地实现还是相对比较优美(复杂)的q
Code:
- #include<iostream>
- #include<cstdio>
- #include<cmath>
- #include<algorithm>
- #define inf 2147483647
- using namespace std;
- int a[],n,k;
- struct search_tree
- {
- int minn;
- int maxn;
- }q;
- struct Segtree
- {
- int minv[],maxv[];
- void pushup(int rt)
- {
- maxv[rt] = max(maxv[rt<<],maxv[rt<<|]);
- minv[rt] = min(minv[rt<<],minv[rt<<|]);
- }
- void build(int rt,int l,int r)
- {
- if(l == r)
- {
- maxv[rt] = a[l];
- minv[rt] = a[l];
- return ;
- }
- int mid = (l + r)>>;
- build(rt<<,l,mid);
- build(rt<<|,mid+,r);
- pushup(rt);
- }
- search_tree solve(int rt,int l,int r,int ll,int rr) //ll rr 为待求量
- {
- if(ll <= l && rr >= r)
- return (search_tree)
- {
- minv[rt],
- maxv[rt]
- };
- int mid = (l+r)>>;
- int minn = inf , maxn = -inf;
- search_tree ans;
- if(ll <= mid)
- {
- ans = solve(rt<<,l,mid,ll,rr);
- maxn = max(maxn,ans.maxn);
- minn = min(minn,ans.minn);
- }
- if(rr > mid)
- {
- ans = solve(rt<<|,mid+,r,ll,rr);
- maxn = max(maxn,ans.maxn);
- minn = min(minn,ans.minn);
- }
- return (search_tree)
- {
- minn,
- maxn
- };
- }
- }segtree;
- int main()
- {
- scanf("%d%d",&n,&k);
- for(int i=;i<=n;i++)
- scanf("%d",&a[i]);
- segtree.build(,,n);
- for(int i=;i<=n - k + ;i++)
- {
- q = segtree.solve(,,n,i,i + k - );
- printf("%d ",q.minn);
- a[i] = q.maxn;
- }
- printf("\n");
- for(int i=;i<=n-k+;i++)
- printf("%d ",a[i]);
- return ;
- }
(三)单调队列
单调队列概念:
队列中的元素其对应在原来的列表中的顺序必须是单调递增的。
队列中元素的大小必须是单调递*(增/减/甚至是自定义也可以)
这保证了单调队列的双有序
但是单调队列有一个特殊的特点就是可以双向操作出队。
但是我们并不是把单调队列里的每一个数都要存一遍,我们只需要存储这些单调队列里有序环境中有序的数(即我们所要求的目的)
这个概念还是很抽象的q
不过从这个题来看还是可以有所帮助的q
并不是每一个数的记录都是有意义的;
我们只需要存储那些对于我们来说有意义的数值;
以此题求最小值为栗子:
若有ai和aj两个数,且满足i<j。
如果ai>aj,那么两个数都应该记录;
但是如果ai≤aj,那么当aj进入区间后,ai的记录就没有意义了。
我们假设每个数能作为区间最大值的次数(即它可以存在区间内的次数)为它的贡献,当aj进入区间以后,在区间中存在的时间一定比ai长,也就说明ai一定不会再做贡献了;
我们确定没有贡献的点,便可以直接删去
Code:
- #include<iostream>
- #include<cstdio>
- #include<cstring>
- #include<algorithm>
- #define ll long long
- #define MAXN 1008666
- using namespace std;
- struct Node
- {
- int v;
- int pos;
- }node[MAXN << ];
- int n,a[MAXN << ],h = ,t,k;
- int m;
- int main()
- {
- scanf("%d%d",&n,&k);
- for(int i=;i<=n;i++)
- scanf("%d",&a[i]);
- for(int i=;i<=n;i++) //维护单调递减队列
- {
- while(h <= t && node[h].pos + k <= i)
- h++;
- while(h <= t && node[t].v >= a[i])
- t--;
- node[++t].v = a[i];
- node[t].pos = i;
- if(i >= k)
- printf("%d ",node[h].v);
- }
- h = ;
- t = ;
- printf("\n");
- for(int i=;i<=n;i++) //维护单调递增队列
- {
- while(h <= t && node[h].pos + k <= i)
- h++;
- while(h <= t && node[t].v <= a[i])
- t--;
- node[++t].v = a[i];
- node[t].pos = i;
- if(i >= k)
- printf("%d ",node[h].v);
- }
- return ;
- }
[洛谷P1886]滑动窗口 (单调队列)(线段树)的更多相关文章
- 洛谷 P1886 滑动窗口(单调队列)
题目链接 https://www.luogu.org/problemnew/show/P1886 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始 ...
- 洛谷P1886 滑动窗口(POJ.2823 Sliding Window)(区间最值)
To 洛谷.1886 滑动窗口 To POJ.2823 Sliding Window 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每 ...
- 洛谷P4198 楼房重建 单调栈+线段树
正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...
- 洛谷 P1886 滑动窗口(单调队列)
嗯... 题目链接:https://www.luogu.org/problem/P1886 首先这道题很典型,是标准的单调队列的模板题(也有人说单调队列只能解决这一个问题).这道题可以手写一个队列,也 ...
- [Luogu P1886]滑动窗口--单调队列入门
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- 洛谷 P1886 滑动窗口 (数据与其他网站不同。。)
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- 洛谷 P1886 滑动窗口
题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...
- 洛谷——P1886 滑动窗口|| POJ——T2823 Sliding Window
https://www.luogu.org/problem/show?pid=1886#sub || http://poj.org/problem?id=2823 题目描述 现在有一堆数字共N个数字( ...
- [POJ2823][洛谷P1886]滑动窗口 Sliding Window
题目大意:有一列数,和一个窗口,一次能框连续的s个数,初始时窗口在左端,不断往右移动,移到最右端为止,求每次被框住的s个数中的最小数和最大数. 解题思路:这道题是一道区间查询问题,可以用线段树做.每个 ...
随机推荐
- sticky footer 模板
http://www.w3cplus.com/blog/tags/136.html http://www.w3cplus.com/css/css-sticky-foot-at-bottom-of-th ...
- Zookeeper客户端Curator的使用,简单高效
Curator是Netflix公司开源的一个Zookeeper客户端,与Zookeeper提供的原生客户端相比,Curator的抽象层次更高,简化了Zookeeper客户端的开发量. 1.引入依赖: ...
- LeetCode(116):填充同一层的兄弟节点
Medium! 题目描述: 给定一个二叉树 struct TreeLinkNode { TreeLinkNode *left; TreeLinkNode *right; TreeLinkNode *n ...
- django----Form实时更新两种方式
在ModelForm需要知道: from app03 import models from django.forms import ModelForm class UserForm(ModelForm ...
- Python交换a,b两个数值的三种方式
# coding:utf-8 a = 1 b = 2 # 第一种方式 # t = a # 临时存放变量值 # a = b # b = t # 第二种方式 # a = a + b # a的值已经不是原始 ...
- Python之argv简明详解
今日看到argv 度娘查找一番,基本都是转载的同一篇文章,总体字数不少但看了之后感觉还是稀里糊涂,自己尝试了一番简单总结如下 当我们需要在命令行执行脚本并需要在执行脚本的同时传入参数给脚本使用,那我们 ...
- MySQL监控系统Lepus的搭建
现在流行的监控系统很多,选择一个合适自己的就可以了,例如Zabbix.Nagios:监控MySQL为主的有MySQLMTOP.Lepus.本文主要介绍快速部署lepus以及监控MySQL,因为作为DB ...
- spring cloud Eureka注册中心集群搭建
1.创建springcloud-eureka maven项目 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0&quo ...
- 饮冰三年-人工智能-linux-07 硬盘分区、格式化及文件系统的管理
先给虚拟机添加一个硬盘 通过fdisk -l sdb,查看磁盘内容 通过fdisk /sdb 来操作分区 创建一个新分区 创建第二个分区 创建第三个分区 创建扩展分区 再次创建分区,其实使用的是扩展分 ...
- virtualenv and virtualenvwrapper
virtualenv 1.下载virtualenv工具 通过物理环境的pip工具安装 清华 国内 pip3 install -i https://pypi.tuna.tsinghua.edu.cn/ ...