---恢复内容开始---

这是很好的一道题

题目描述:

现在有一堆数字共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 ;
}

(三)单调队列

单调队列概念:

  1. 队列中的元素其对应在原来的列表中的顺序必须是单调递增的。

  2. 队列中元素的大小必须是单调递*(增/减/甚至是自定义也可以)

这保证了单调队列的双有序

但是单调队列有一个特殊的特点就是可以双向操作出队。

但是我们并不是把单调队列里的每一个数都要存一遍,我们只需要存储这些单调队列里有序环境中有序的数(即我们所要求的目的)

这个概念还是很抽象的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]滑动窗口 (单调队列)(线段树)的更多相关文章

  1. 洛谷 P1886 滑动窗口(单调队列)

    题目链接 https://www.luogu.org/problemnew/show/P1886 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始 ...

  2. 洛谷P1886 滑动窗口(POJ.2823 Sliding Window)(区间最值)

    To 洛谷.1886 滑动窗口 To POJ.2823 Sliding Window 题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每 ...

  3. 洛谷P4198 楼房重建 单调栈+线段树

    正解:单调栈+线段树 解题报告: 传送门! 首先考虑不修改的话就是个单调栈板子题昂,这个就是 然后这题的话,,,我怎么记得之前考试好像有次考到了类似的题目昂,,,?反正我总觉着这方法似曾相识的样子,, ...

  4. 洛谷 P1886 滑动窗口(单调队列)

    嗯... 题目链接:https://www.luogu.org/problem/P1886 首先这道题很典型,是标准的单调队列的模板题(也有人说单调队列只能解决这一个问题).这道题可以手写一个队列,也 ...

  5. [Luogu P1886]滑动窗口--单调队列入门

    题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...

  6. 洛谷 P1886 滑动窗口 (数据与其他网站不同。。)

    题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...

  7. 洛谷 P1886 滑动窗口

    题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array i ...

  8. 洛谷——P1886 滑动窗口|| POJ——T2823 Sliding Window

    https://www.luogu.org/problem/show?pid=1886#sub || http://poj.org/problem?id=2823 题目描述 现在有一堆数字共N个数字( ...

  9. [POJ2823][洛谷P1886]滑动窗口 Sliding Window

    题目大意:有一列数,和一个窗口,一次能框连续的s个数,初始时窗口在左端,不断往右移动,移到最右端为止,求每次被框住的s个数中的最小数和最大数. 解题思路:这道题是一道区间查询问题,可以用线段树做.每个 ...

随机推荐

  1. android中调用c++文件并转为so

    1.新建项目,不选include support c++ 报错:Error:Failed to open zip file.Gradle's dependency cache may be corru ...

  2. linux cp命令使用

    功能: 复制文件或目录说明: cp指令用于复制文件或目录,如同时指定两个以上的文件或目录,且最后的目的地是一个已经存在的目录,则它会把前面指定的所有文件或目录复制到此目录中.若同时指定多个文件或目录, ...

  3. linux 源码安装PHP

    解压: 解压完: configure: configure成功: make: make完成: 安装完成!!! 测试: 需要./bin/php来运行php 想要任何目录输入PHP就能使用php 方法一: ...

  4. java基础概念整理(三)

    1.对象的上转型 对象的上转型不能调用和使用子类对象新增的成员和变量,不能调用子类新增的方法. 上转型对象可以访问子类继承或者隐藏的成员变量,也可以调用子类继承或者子类重写的实例方法.因此如果子类重写 ...

  5. Chrome浏览器常用键盘快捷键介绍

    很多人喜欢使用键盘快捷键来操作电脑,因为在熟练的情况下,使用键盘会比使用鼠标点击更快.更高效.本文对Chrome浏览器常用的快捷键做个说明. 标签页和窗口快捷键 1.  Ctrl + n 打开新窗口 ...

  6. linux安装python3+selenium

    安装笔记 当前安装使用centos7 安装python3 1.下载 [admin@ ~] wget https://www.python.org/ftp/python/3.6.0/Python-3.6 ...

  7. 论文阅读笔记三十:One pixel attack for fooling deep neural networks(CVPR2017)

    论文源址:https://arxiv.org/abs/1710.08864 tensorflow代码: https://github.com/Hyperparticle/one-pixel-attac ...

  8. centos7.4/rehat7.0系统安装

    以下是安装过程:(图解),以下是rehat为例 这里可以改为centos的镜像 之后就可以用了,记得做快照!!! 拓展:分离使用 效果:

  9. Android自定义View+贝赛尔曲线

    Android -- 贝塞尔曲线公式的推导和简单使用https://www.cnblogs.com/wjtaigwh/p/6647114.html Android -- 贝塞尔使圆渐变为桃心http: ...

  10. Debug.Assert vs Exception Throwing(转载)

    来源 Q: I've read plenty of articles (and a couple of other similar questions that were posted on Stac ...