POJ 2823 Sliding Window

题目

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 knumbers 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 positionMinimum valueMaximum 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

题目大意

 

给定一个数列,从左至右输出每个长度为m的数列段内的最小数和最大数。

数列长度:N<=10^6,m<=N (以最大值为例)

 

8 3

 

1 3 -1 -3 5 3 6 7

 

 

 

3 3 5 5 6 7

 

分析

    首先我们在找f(i)时,当前前面已经找过了,重新找就会浪费时间,那么如何保存上一次的结果呢?

    所以我们要用到单调队列

    

    使用单调队列就涉及到去头和删尾:

    单调队列具有队列内所有元素不是单调递增就是单调递减的性质,所以每次的最小(最大)值一定会在队首

    程序实现过程中先将前k个元素入队,此后每次在队尾加入a[k+1...n],在插入元素中同时进行以下操作:

  1. 将队尾所有大于或小于a[i]的值弹出队列
  2. 插入a[i]到队尾
  3. 判断队首元素位置是否超出i-k

    每次取对头输出就好了

代码

 

 1 #include<iostream>
 2 #include<queue>
 3 #include<cstdio>
 4 #define N 1000000
 5 using namespace std;
 6 int a[N+1];
 7 int q[N+1];
 8 int qq[N+1];
 9 int main ()
10 {
11     int n,m;
12     scanf("%d %d",&n,&m);
13     for (int i=1;i<=n;i++)
14        scanf("%d",&a[i]);
15     q[1]=1;
16     if (m==1) cout<<a[q[1]]<<" ";  //特判
17     int h=1,t=1;
18     for (int i=2;i<=n;i++)  //找最小
19     {
20         while (h<=t&&a[q[t]]>=a[i]) t--;  //当我加进来的数比队位小,那么就要插队向前找 
21         q[++t]=i;   //存放下标
22         while (i-q[h]>=m) h++;  //当超出我当前的范围值时,头指针后移
23         if (i>=m) printf("%d ",a[q[h]]);
24     }
25     cout<<endl;
26     qq[1]=1;
27     if (m==1) cout<<a[qq[1]]<<" ";
28     h=1,t=1;
29     for (int i=2;i<=n;i++)
30     {
31         while (h<=t&&a[qq[t]]<=a[i]) t--;
32         qq[++t]=i;
33         while (i-qq[h]>=m) h++;
34         if (i>=m) printf("%d ",a[qq[h]]);
35     }

 

posted @ 2019-01-05 16:12  Melted_czj  阅读(134)  评论(0编辑  收藏  举报
body { background-color:whitesmoke; } // 修改背景颜色为半透明 #home,#sideBarMain>div,#blog-sidecolumn>div>div,.catListView{ background-color:rgba(255,255,255,0); } // 修改其他边框的颜色