[洛谷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 配置自动备份
			
希望配置 Confluence 备份: 进入 > 基本配置(General Configuration) > 备份管理(Backup administration). 选择 编辑(Edi ...
 - nginx实践(五)之代理服务(正向代理与反向代理介绍)
			
正向代理 正向代理代理是为客户端服务,代理负责DNS解析域名到对应ip,并进行访问服务端,返回响应给客户端 反向代理 客户端自己负责请求DNS解析域名到对应ip,服务端通过代理分发流量,进行负载均衡 ...
 - SpringBoot实现异步
			
1.创建AsyncTest类 package com.cppdy.service; import org.springframework.scheduling.annotation.Async; im ...
 - SpringMVC国际化与文件上传
			
点击阅读上一章 其实SpringMVC中的页面国际化与上一章的验证国际化基本一致. 1.对页面进行国际化 1)首先我们对Spring配置文件中添加国际化bean配置 <!-- 注册国际化信息,必 ...
 - 【python】mongo删除数据
			
参考:https://stackoverflow.com/questions/23334743/setting-justone-limiter-for-pymongo-remove-throws-ty ...
 - 使用Navicat快速生成数据库字典
			
https://blog.csdn.net/maquealone/article/details/60764420
 - bzoj2973转移矩阵构造法!
			
/* 构造单位矩阵(转移矩阵) 给定n*m网格,每个格子独立按照长度不超过6的操作串循环操作 对应的操作有 0-9:拿x个石头到这个格子 nwse:把这个格子的石头推移到相邻格子 d:清空该格石子 开 ...
 - txt提取相同内容、不同内容
			
findstr >相同部分.txt findstr >%~n2多余部分.txt findstr >%~n1多余部分.txt
 - 80端口被占用 导致apach无法启动问题
			
1.查找是哪个程序占用了80端口 netstat -ano 列出所有进程 观察 “本地地址” 列 找到对应的PID 我这里是4 简单的办法,打开任务管理器,查看PID是4的 是哪个进程. 发现是Sys ...
 - labelme连续将文件夹中的json文件进行可视化的指令
			
for /r C:\Users\Fourmi\Desktop\ZP0 %i in (*.json) do labelme_json_to_dataset %i