博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
P1886 滑动窗口
阅读量:5366 次
发布时间:2019-06-15

本文共 2714 字,大约阅读时间需要 9 分钟。

题目描述

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

例如:

The array is [1 3 -1 -3 5 3 6 7], and k = 3.

输入输出格式

输入格式:

 

输入一共有两行,第一行为n,k。

第二行为n个数(<INT_MAX).

 

输出格式:

 

输出共两行,第一行为每次窗口滑动的最小值

第二行为每次窗口滑动的最大值

 

输入输出样例

输入样例#1: 
8 31 3 -1 -3 5 3 6 7
输出样例#1: 
-1 -3 -3 -3 3 33 3 5 5 6 7

说明

50%的数据,n<=10^5

100%的数据,n<=10^6

 

/*维护一个下标递增、值也递增的队列。当扫描到第 i 个数时,将队头下标<=i-k的数删掉(把入队时间太长的给删掉,因为已经没有用了),同时将第 i个数插入,此时队头元素即为所求最小值。*/ #include
#include
#include
#include
#include
#include
#define N 1000005using namespace std;inline int read(){ int sum=0,f=1;char c=getchar(); for(;(c<'0'||c>'9')&&c!='-';c=getchar()); if(c=='-'){f=-1;c=getchar();} for(;c>='0'&&c<='9';c=getchar()){sum=sum*10+c-'0';} return sum*f;}int n,k,a[N];int que[N],head,tail,id[N]; //que是单调队列,id是对应编号。void mymin(){ head=1; tail=0; for(int i=1;i<=n;++i) { while(head<=tail&&que[tail]>=a[i]) tail--; //只要队列里有元素,并且尾元素比待处理值大,即表示尾元素已经不可能出场,直到尾元素小于待处理值 que[++tail]=a[i]; //待处理值入队 id[tail]=i; //存下其编号 while(id[head]<=i-k) head++; //如果队首元素已经"过时",出队 if(i>=k) printf("%d ",que[head]);//输出最值,即队首元素。i>=k输出 } printf("\n");}void mymax() //找最大值,和最小值德操作反着 { head=1; tail=0; for(int i=1;i<=n;++i) { while(head<=tail&&que[tail]<=a[i]) tail--; que[++tail]=a[i]; id[tail]=i; while(id[head]<=i-k) head++; if(i>=k) printf("%d ",que[head]); } printf("\n");}int main(){ n=read();k=read(); for(int i=1;i<=n;++i) { a[i]=read(); } mymin(); mymax(); return 0;}
单调队列版

 

/*一开始写的线段树,TLE了最后一个点,讨论里说正解是模拟。。。这道题线段树并不难写,但是时间复杂度的原因会TLE。后来加了个特判,当k==1时按原样输出就过了。 */#include
#include
#include
#include
#include
#define N 1000005using namespace std;int n,k,maxn,minn;int num[N],min_tree[N*4],max_tree[N*4];int max_ans[N],min_ans[N];void build(int root,int l,int r){ if(l==r) //找叶节点,对应原数组 { max_tree[root]=num[l]; //存当前子树中的最大值 min_tree[root]=num[l]; //存当前子树中的最小值 return; } int mid=(l+r)>>1; build(root<<1,l,mid); //建左子树 build(root<<1|1,mid+1,r); //建右子树 max_tree[root]=max(max_tree[root<<1],max_tree[root<<1|1]); //求当前子树中的最大值 min_tree[root]=min(min_tree[root<<1],min_tree[root<<1|1]); //求最小值 }void query(int root,int l,int r,int L,int R){ if(L<=l&&r<=R) //查询区间包含当前区间,直接调用当前区间的值 { maxn=max(maxn,max_tree[root]); //最大的 minn=min(minn,min_tree[root]); //最小的 return; } int mid=(l+r)>>1; if(L<=mid) query(root<<1,l,mid,L,R); //找查询区间在线段树中的范围 if(mid
线段树版

 

转载于:https://www.cnblogs.com/lovewhy/p/8717405.html

你可能感兴趣的文章
MES架构
查看>>
hdu 2767(tarjan)
查看>>
sklearn之分类模型混淆矩阵和分类报告
查看>>
MySQL各存储引擎
查看>>
项目--简单导出CSV文件
查看>>
Oracle session相关数据字典(一)
查看>>
C#用正则表达式 获取网页源代码标签的属性或值
查看>>
BZOJ 3399 [Usaco2009 Mar]Sand Castle城堡(贪心)
查看>>
WCF(一) 简单的认知
查看>>
[MFC][DShow]简单例子
查看>>
js onclick事件传参
查看>>
WiCloud 商业Wi-Fi管理平台
查看>>
团队项目--未完待续
查看>>
双重标准,我该怎么解决
查看>>
python中的网页标签等字符处理
查看>>
Linux常用命令(十二)
查看>>
Linux常用命令(十五)
查看>>
Linux常用命令(十四)
查看>>
Linux常用命令(十七)
查看>>
Linux常用命令(十六)
查看>>