poj 2823 Sliding Window
http://poj.org/problem?id=2823
单调队列的启蒙题。
Sliding Window
Time Limit: 12000MS | Memory Limit: 65536K | |
Total Submissions: 39404 | Accepted: 11680 | |
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
单调队列,顾名思义就是具有单调性的队列O(∩_∩)O~,一般的队列只能从队尾入队、队首出队;为了保持单调队列的单调性,单调队列除具有这两种性质外,还可以从队尾出队。
以单增的单调队列为例,当元素t要入队时,先要从队尾依次弹出所有>=t的元素,再将t加在队尾。
举个例子,如果序列:1 3 -1 -3 10要构成单调队列,
先将元素“1”放入队列中,以初始化队列,
接着元素“3”要入队,队尾元素“1”比“3”小,因此“3”可以直接入队,队列变为1 3,
接着“-1”要入队,从队尾依次弹出元素“3”“1”后将“-1”入队,队列变为-1,
同理“-3”入队后,队列变为-3,
“10”入队后,队列变为-3 10
单调队列有什么用呢?看一道例题:(poj2823)
给定含有n个元素的无序序列a[],和一个整数k,要求求出a[]中每连续k个元素组成的序列中的最小值(或最大值),这样的值可能有1个或n-k+1个。
比较简单的方式,是每次都将k个数排序后输出最值,具有O(N^2logN)的时间复杂度。但如果用单调队列的话,我们可以在O(N)的时间内求解,原因是每个元素最多入队一次、出队一次。
要解决该题,我们还要记录每个元素在原序列中的位置p,每次只需从队首开始找到跟当前元素a[i]距离不大于k的元素(即是i-p+1<=k)输出即可。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 struct node 5 { 6 int p; 7 int num; 8 }q[1000005],q1[1000005]; 9 int r,f,g,ff; 10 int a[1000005]; 11 void inquene(int i) 12 { 13 while(q[--r].num>a[i]&&r>=f); 14 // printf("r1=%d\n",r); 15 q[++r].p=i; 16 // printf("r2=%d\n",r); 17 q[r].num=a[i]; 18 r++; 19 // printf("r3=%d\n",r); 20 } 21 void dequene(int i) 22 { 23 while(q1[--g].num<a[i]&&g>=ff); 24 q1[++g].p=i; 25 q1[g].num=a[i]; 26 g++; 27 } 28 int main() 29 { 30 int n,k,i; 31 while(~scanf("%d%d",&n,&k)) 32 { 33 for(i=1;i<=n;i++) 34 scanf("%d",&a[i]); 35 r=g=2;f=ff=1; 36 q[1].p=1; 37 q[1].num=a[1]; 38 for(i=2;i<=k&&i<=n;i++) 39 { 40 inquene(i); 41 } 42 printf("%d",q[f].num); 43 for(;i<=n;i++) 44 { 45 inquene(i); 46 while(i-q[f].p>=k) 47 f++; 48 // printf("f=%d\n",f); 49 printf(" %d",q[f].num); 50 } 51 printf("\n"); 52 q1[1].p=1; 53 q1[1].num=a[1]; 54 for(i=2;i<=k&&i<=n;i++) 55 { 56 dequene(i); 57 } 58 printf("%d",q1[ff].num); 59 for(;i<=n;i++) 60 { 61 dequene(i); 62 while(i-q1[ff].p>=k) 63 ff++; 64 // printf("f=%d\n",f); 65 printf(" %d",q1[ff].num); 66 } 67 printf("\n"); 68 } 69 return 0; 70 }