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

这是很好的一道题

题目描述:

现在有一堆数字共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. Confluence 6 降级你的许可证

    如果你决定降级你 Confluence 的许可证而削减你的许可证开支,你需要确定当前已经直排的用户许可证数量(在用户许可证页面中)要少于你希望应用的新的许可证的允许用户数量,在你应用新许可证的时候. ...

  2. 声明寄存器ROM

    :] ROM [:] ; integer i; initial begin ;i<=;i=i+) begin ROM[i] <= {{'b0}}; end end 同时可以考虑双端口ROM ...

  3. TabLayout和ViewPager

    这里就说下tablayout+viewpager的实现方式:tablayout是android5.0推出来的一个MaterialDesign风格的控件,是专门用来实现tab栏效果的:功能强大,使用方便 ...

  4. requests 的基本用法

    r = requests.get('www.baidu.com') r.request.headers{'User-Agent': 'python-requests/2.18.4', 'Accept- ...

  5. LeetCode(88):合并两个有序数组

    Easy! 题目描述: 给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组. 说明: 初始化 nums1 和 nums2 的元素 ...

  6. Ubuntu shutdown now 关机后 开机黑屏

    一重装gdm3      失败 sudo apt-get remove --purge nvidia-* # 卸载nvidia相关组件 sudo apt purge gdm gdm3 # 卸载gdm和 ...

  7. javaSocket笔记

    1.查看电脑当前开放链接的端口号 使用netstat命令 netstat -nao 可以查看PID进程号 netstat -nab 获取进程的详细信息 2.类创建的不同对象,引用是不同的.也就是说同一 ...

  8. typeof操作符--undefined与null

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>ty ...

  9. 火狐浏览器无故卡死,未响应或者占大量cpu资源解决方案

    这是火狐社区的文章,对火狐浏览器无故卡死,未响应或者占大量cpu资源有详细的说明和解决,记录下!!! ++++++++++++++++++++++++++++++++ Firefox 挂起 如果您的 ...

  10. Python数据分析几个比较常用的方法

    1,表头或是excel的索引如果是中文的话,输出会出错 ​​解决方法:python的版本问题!换成python3就自动解决了!当然也有其他的方法,这里就不再深究 2,如果有很多列,如何输出指定的列? ...