Time Limit: 12000MS   Memory Limit: 65536K
Total Submissions: 58002   Accepted: 16616
Case Time Limit: 5000MS

Description

An array of size n ≤ 106 is given to you. There is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves rightwards by one position. Following is an example: 
The array is [1 3 -1 -3 5 3 6 7], and k is 3.

Window position Minimum value Maximum value
[1  3  -1] -3  5  3  6  7  -1 3
 1 [3  -1  -3] 5  3  6  7  -3 3
 1  3 [-1  -3  5] 3  6  7  -3 5
 1  3  -1 [-3  5  3] 6  7  -3 5
 1  3  -1  -3 [5  3  6] 7  3 6
 1  3  -1  -3  5 [3  6  7] 3 7

Your task is to determine the maximum and minimum values in the sliding window at each position.

Input

The input consists of two lines. The first line contains two integers n and k which are the lengths of the array and the sliding window. There are n integers in the second line. 

Output

There are two lines in the output. The first line gives the minimum values in the window at each position, from left to right, respectively. The second line gives the maximum values. 

Sample Input

8 3
1 3 -1 -3 5 3 6 7

Sample Output

-1 -3 -3 -3 3 3
3 3 5 5 6 7

Source

题目描述

现在有一堆数字共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 3
1 3 -1 -3 5 3 6 7
输出样例#1:

-1 -3 -3 -3 3 3
3 3 5 5 6 7

说明

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

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

思路:单调队列。

分别维护一个单调上升队列和一个单调下降队列即可。

拿区间最大值来说吧,一个上升队列,它的队首值就是区间最大值。

如果窗口向后滑动,首先,在满足队列单调的前提下,把新值加入(不一定真的加入)。

如果队首值等于要去掉的值,队首后移。

代码实现:

 #include<cstdio>
#define maxn 1000010
int n,k,s[maxn];
int a;
int h1,t1,q1[maxn],a1[maxn],l1;
int h2,t2,q2[maxn],a2[maxn],l2;
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&s[i]);
a=h1-;h1=t1;
for(int j=a;j>=t1;j--) if(s[i]>=q1[j]){h1=j+;break;}
q1[h1++]=s[i];
if(i>k&&s[i-k]==q1[t1]) t1++;//因为判断先后的问题,一直RE一个点。
if(i>=k) a1[l1++]=q1[t1];
a=h2-;h2=t2;
for(int j=a;j>=t2;j--) if(s[i]<=q2[j]){h2=j+;break;}
q2[h2++]=s[i];
if(i>k&&s[i-k]==q2[t2]) t2++;
if(i>=k) a2[l2++]=q2[t2];
}
for(int i=;i<l1;i++) printf("%d ",a1[i]);putchar('\n');
for(int i=;i<l2;i++) printf("%d ",a2[i]);putchar('\n');
return ;
}

另一种写法(更工整些):

 #include<cstdio>
#define maxn 1000010
int n,k,s[maxn];
int a;
int h1,t1,q1[maxn],a1[maxn],l1;
int h2,t2,q2[maxn],a2[maxn],l2;
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&s[i]);
q1[h1++]=;q2[h2++]=-;
for(int j=t1;j<h1;j++)
if(s[i]<q1[j]){q1[j]=s[i];h1=j+;break;}
if(i>k&&s[i-k]==q1[t1]) t1++;
if(i>=k) a1[l1++]=q1[t1];
for(int j=t2;j<h2;j++)
if(s[i]>q2[j]){q2[j]=s[i];h2=j+;break;}
if(i>k&&s[i-k]==q2[t2]) t2++;
if(i>=k) a2[l2++]=q2[t2];
}
for(int i=;i<l1;i++) printf("%d ",a1[i]);putchar('\n');
for(int i=;i<l2;i++) printf("%d ",a2[i]);putchar('\n');
return ;
}

也可以分开写:

 #include<cstdio>
#define maxn 1000010
int n,k,a,h,t;
int s[maxn],q[maxn];
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&s[i]);
q[h++]=;
for(int j=t;j<h;j++) if(s[i]<q[j]){q[j]=s[i];h=j+;break;}
if(i>k&&s[i-k]==q[t]) t++;
if(i>=k) printf("%d ",q[t]);
}
putchar('\n');h=t=;
for(int i=;i<=n;i++){
q[h++]=-;
for(int j=t;j<h;j++) if(s[i]>q[j]){q[j]=s[i];h=j+;break;}
if(i>k&&s[i-k]==q[t]) t++;
if(i>=k) printf("%d ",q[t]);
}
putchar('\n');
return ;
}

越来越短。

最后被poj G++接受的代码(2266mm):

 #include<cstdio>
#define maxn 1000010
int n,k,s[maxn];
int a;
int h1,t1,q1[maxn],a1[maxn],l1;
int h2,t2,q2[maxn],a2[maxn],l2;
inline int abs(int x){return x<?-x:x;}
void write(int x){
if(x) write(x/);
else return;
putchar(x%+'');
}
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++){
scanf("%d",&s[i]);
a=h1-;h1=t1;
for(int j=a;j>=t1;j--) if(s[i]>=q1[j]){h1=j+;break;}
q1[h1++]=s[i];
if(i>k&&s[i-k]==q1[t1]) t1++;
if(i>=k) a1[l1++]=q1[t1];
a=h2-;h2=t2;
for(int j=a;j>=t2;j--) if(s[i]<=q2[j]){h2=j+;break;}
q2[h2++]=s[i];
if(i>k&&s[i-k]==q2[t2]) t2++;
if(i>=k) a2[l2++]=q2[t2];
}
for(int i=;i<l1;i++){
if(a1[i]<) putchar('-');
write(abs(a1[i]));
if(!a1[i]) putchar('');
if(i<l1-) putchar(' ');
}
putchar('\n');
for(int i=;i<l2;i++){
if(a2[i]<) putchar('-');
write(abs(a2[i]));
if(!a2[i]) putchar('');
if(i<l2-) putchar(' ');
}
putchar('\n');
return ;
}

除了最后一个 G++ 格式都T了,C++却能A,不知道为什么。

洛谷70分T掉的线段树

 #include<cstdio>
const int maxn=4e6;
int n,k;
int s[maxn];
int t_min[maxn],t_max[maxn];
inline int min_(int x,int y){return x<y?x:y;}
inline int max_(int x,int y){return x>y?x:y;}
void build_min(int k,int l,int r){
if(l==r){
t_min[k]=s[l];
return;
}
int mid=l+r>>,ls=k<<,rs=ls|;
build_min(ls,l,mid);
build_min(rs,mid+,r);
t_min[k]=t_min[ls]<t_min[rs]?t_min[ls]:t_min[rs];
}
int search_min(int k,int l,int r,int al,int ar){
if(al==l&&ar==r) return t_min[k];
int ret=1e9,mid=l+r>>,ls=k<<,rs=ls|;
if(al<=mid) ret=min_(ret,search_min(ls,l,mid,al,min_(ar,mid)));
if(ar>mid) ret=min_(ret,search_min(rs,mid+,r,max_(al,mid+),ar));
return ret;
}
void build_max(int k,int l,int r){
if(l==r){
t_max[k]=s[l];
return;
}
int mid=l+r>>,ls=k<<,rs=ls|;
build_max(ls,l,mid);
build_max(rs,mid+,r);
t_max[k]=t_max[ls]>t_max[rs]?t_max[ls]:t_max[rs];
}
int search_max(int k,int l,int r,int al,int ar){
if(al==l&&ar==r) return t_max[k];
int ret=-1e9,mid=l+r>>,ls=k<<,rs=ls|;
if(al<=mid) ret=max_(ret,search_max(ls,l,mid,al,min_(ar,mid)));
if(ar>mid) ret=max_(ret,search_max(rs,mid+,r,max_(al,mid+),ar));
return ret;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<=n;i++) scanf("%d",&s[i]);
build_min(,,n);
build_max(,,n);
for(int i=;i<=n-k+;i++)
printf("%d ",search_min(,,n,i,i+k-));
putchar('\n');
for(int i=;i<=n-k+;i++)
printf("%d ",search_max(,,n,i,i+k-));
putchar('\n');
return ;
}

常数优化十分可观的zkw线段树(洛谷 2275ms)

 #include<cstdio>
const int maxn=<<;
int n,k,m;
int t[maxn];
inline int min_(int x,int y){return x<y?x:y;}
inline int max_(int x,int y){return x>y?x:y;}
void build_min(){for(int i=m-;i>;i--) t[i]=min_(t[i<<],t[i<<|]);}
int search_min(int l,int r,int ret){
for(l+=m,r+=m;r-l!=;l>>=,r>>=){
if(~l&) ret=min_(ret,t[l^]);
if(r&) ret=min_(ret,t[r^]);
}
return ret;
}
void build_max(){for(int i=m-;i>;i--) t[i]=max_(t[i<<],t[i<<|]);}
int search_max(int l,int r,int ret){
for(l+=m,r+=m;r-l!=;l>>=,r>>=){
if(~l&) ret=max_(ret,t[l^]);
if(r&) ret=max_(ret,t[r^]);
}
return ret;
}
int main(){
scanf("%d%d",&n,&k);
for(m=;m<=n+;m<<=);
for(int i=;i<=n;i++) scanf("%d",t+m+i);
build_min();
for(int i=;i<=n-k;i++)
printf("%d ",search_min(i,i+k+,1e9));
putchar('\n');
build_max();
for(int i=;i<=n-k;i++)
printf("%d ",search_max(i,i+k+,-1e9));
putchar('\n');
return ;
}

题目来源:POJ,洛谷

Sliding Window(滑动窗口)的更多相关文章

  1. [POJ2823]Sliding Window 滑动窗口(单调队列)

    题意 刚学单调队列的时候做过 现在重新做一次 一个很经典的题目 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗 ...

  2. 【POJ 2823】【Luogu P1886】Sliding Window 滑动窗口

    POJ 2823 Luogu P1886 [解题思路] 这是一个单调队列算法的经典题目,几乎学习单调队列的人都接触过这题. 利用单调队列算法求出每一个固定区间内的最(大/小)值. 以下以最大值为例: ...

  3. Spark-Streaming之window滑动窗口应用

    Spark-Streaming之window滑动窗口应用,Spark Streaming提供了滑动窗口操作的支持,从而让我们可以对一个滑动窗口内的数据执行计算操作.每次掉落在窗口内的RDD的数据,会被 ...

  4. 57、Spark Streaming: window滑动窗口以及热点搜索词滑动统计案例

    一.window滑动窗口 1.概述 Spark Streaming提供了滑动窗口操作的支持,从而让我们可以对一个滑动窗口内的数据执行计算操作.每次掉落在窗口内的RDD的数据, 会被聚合起来执行计算操作 ...

  5. [LeetCode] Sliding Window Maximum 滑动窗口最大值

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

  6. [LeetCode] Sliding Window Median 滑动窗口中位数

    Median is the middle value in an ordered integer list. If the size of the list is even, there is no ...

  7. LeetCode编程训练 - 滑动窗口(Sliding Window)

    滑动窗口基础 滑动窗口常用来解决求字符串子串问题,借助map和计数器,其能在O(n)时间复杂度求子串问题.滑动窗口和双指针(Two pointers)有些类似,可以理解为往同一个方向走的双指针.常用滑 ...

  8. [Swift]LeetCode239. 滑动窗口最大值 | Sliding Window Maximum

    Given an array nums, there is a sliding window of size k which is moving from the very left of the a ...

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

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

  10. POJ - 2823 Sliding Window (滑动窗口入门)

    An array of size n ≤ 10 6 is given to you. There is a sliding window of size kwhich is moving from t ...

随机推荐

  1. 【第三届强网杯】write up

    一,鲲or鳗orGame 从浏览器里拿到game.gb 用 VisualBoyAdvance ,搜索内存变量,然后改变量就完事了,但是改变量他们说直接利用添加代码功能有bug,所以要在工具里的内存查看 ...

  2. qW3xT.2挖矿病毒处理方案

    我遇到的是一款qW3xT.2的病毒,网上查了一下,好像是挖矿病毒.在此贴一下我找到的关于病毒的资料.这是我的服务器 这篇文章可谓是出自高手之笔,感觉说的很厉害,但是非专业人士的我有点看不懂,看个大概  ...

  3. liunx 用户切换 su sudo

    liunx 用户操作#useradd test#passwd test 用户身份切换su 切换用户 需要知道切换用户的密码1.su [-lm] [-c命令] [username] #su -login ...

  4. Maven之项目搭建与第一个helloworld(多图)

    这次记录第一个搭建一个maven的helloworld的过程. 转载 1.搭建web工程肯定得new 一个 maven工程,假如project中没有直接看到maven工程,那么选择Other,然后在W ...

  5. Linux环境下修改MySQL数据库对表名大小写不敏感

    Linux系统中MySQL对数据库名称和表名是大小写敏感的,这就导致了一些麻烦,虽然已经建立了表和数据,但因为大小写导致无法找到表. MySQL数据库对表名大小写不敏感的设置方法如下: 1.查看MyS ...

  6. PowerDesigner连接Oracle数据库(32位)反向生成物理数据模型

    PowerDesigner可以连接Oracle数据库进行反向生成物理数据模型,本文演示操作过程. 环境说明: 1)Windows8.1,Oracle11R2 32位. 2)PowerDesigner1 ...

  7. php 5.6 版本配置 oracle ddl

    1. Windows版PHP内置了Oracle驱动,在ext目录下:php_oci8.dllphp_oci8_11g.dllphp_pdo_oci.dllLinux上如果自己编译的话则添加下面的con ...

  8. 一个用pyton写的监控服务端进程的软件hcm

    使用udp实现,简单,方便,不用三次握手 1. 所有部署服务器进程的机器有一个代理进程hagent,用来监听hcm console中发送过来的命令 2.hcm需要提供以下命令 start :普通方式启 ...

  9. CAD在网页中如何实现嵌套打印?

    当用户需要打印两个控件的图纸时,可以采用嵌套打印实现.点击此处在线演示. 实现嵌套打印功能,首先将两个控件放入网页中,js代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ...

  10. CAD得到所有实体1

    主要用到函数说明: IMxDrawSelectionSet::AllSelect 得到当前空间的所有实体.详细说明如下: 参数 说明 [in,defaultvalue(NULL)] IMxDrawRe ...