[洛谷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个数中的最小数和最大数. 解题思路:这道题是一道区间查询问题,可以用线段树做.每个 ...
随机推荐
- Confluence 6 针对你的数据库类型确定校验 SQL
不同的数据库通常要求不同的 SQL 校验查询.校验查询通常需要尽可能的简单,这个查询在链接从数据库连接池中取出的时候都会被执行一次. 针对不同的数据库类型,我们推荐先的校验查询 SQL: MySQL ...
- dell g3:安装ubuntu16.04 + CUDA8.0
一.Ubuntu 1.选择UEFI模式启动,参考https://blog.csdn.net/qq_34570910/article/details/78084659 2.卡在logo界面进不去,在qu ...
- python之属性描述符与属性查找规则
描述符 import numbers class IntgerField: def __get__(self, isinstance, owner): print('获取age') return se ...
- bat命令行实现全盘遍历搜索文件
背景:当想要查找一个文件时,记得放在某个盘里.手动去遍历时感觉好心累,找了半天还是没有找着(虽然win有自带的搜索框,但是看着进度条的速度,我便果断的点了取消).基于这个情况,所以写了脚本满足自身查找 ...
- LeetCode(92):反转链表 II
Medium! 题目描述: 反转从位置 m 到 n 的链表.请使用一趟扫描完成反转. 说明:1 ≤ m ≤ n ≤ 链表长度. 示例: 输入: 1->2->3->4->5-&g ...
- jQuery常见的几个文档处理方式
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...
- shell 判断目录是否存在
判断/data/www/logs/wos_log/crontab_log是否, 如果不存在则新建 if [ ! -d "/data/www/logs/wos_log/crontab_log& ...
- Appium Demo
import unittestimport timefrom appium import webdriverfrom public import configimport os #类继承unittes ...
- C# 不使用递归遍历目录树中的文件和文件夹
public class StackBasedIteration { static void Main(string[] args) { // Specify the starting folder ...
- IDEA中tomcat的部署
创建一个项目就要部署tomcat