1. 程式人生 > >POJ2823——Sliding Window 單調佇列入門

POJ2823——Sliding Window 單調佇列入門

Sliding Window
Time Limit: 12000MS Memory Limit: 65536K
Total Submissions: 40596 Accepted: 11992
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

以前做這題貌似用的RMQ,最近由於dp的需要,特意學了下單調佇列

單調佇列是一種支援隊尾入隊,兩端可以出隊的隊,一般會維護一個索引值和value值

拿這題來說,我們以求最大為例,先把前k個入隊,當然需要保證佇列裡是遞減的,這樣最大值才是隊頭,所以每次入隊時,都要和隊尾去比較,加入隊尾太小,那麼就要把隊尾元素出隊,直到可以把元素放進去

當然假如隊頭元素的索引值已經不在此時要求的窗口裡,那麼也要出隊,每一個元素都在第i - k+1到第i個視窗,以此來判斷隊頭是否要出隊

由於這種單調性質,所以單調佇列可以用來優化dp的轉移

#include <map>
#include <set>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 1000010;
int a[N], b[N];
int arr[N];
int x[N], y[N];

int main()
{
	int n, k;
	while(~scanf("%d%d", &n, &k))
	{
		for (int i = 1; i <= n; ++i)
		{
			scanf("%d", &arr[i]);
		}
		if (k > n)
		{
			k = n;
		}
		int front1, rear1, front2, rear2;
		int c1 = 0, c2 = 0;
		front1 = front2 = rear1 = rear2 = 0;
		for (int i = 1; i < k; ++i)
		{
			while (front1 < rear1 && arr[a[rear1 - 1]] <= arr[i])
			{
				rear1--;
			}
			a[rear1++] = i;
			while (front2 < rear2 && arr[b[rear2 - 1]] >= arr[i])
			{
				rear2--;
			}
			b[rear2++] = i;
		}
		for (int i = k; i <= n; ++i)
		{
			while (front1 < rear1 && arr[a[rear1 - 1]] <= arr[i])
			{
				rear1--;
			}
			a[rear1++] = i;
			if (a[front1] < i - k + 1)
			{
				front1++;
			}
			x[++c1] = arr[a[front1]];
			while (front2 < rear2 && arr[b[rear2 - 1]] >= arr[i])
			{
				rear2--;
			}
			b[rear2++] = i;
			if (b[front2] < i - k + 1)
			{
				front2++;
			}
			y[++c2] = arr[b[front2]];
		}
		printf("%d", y[1]);
		for (int i = 2; i <= c2; ++i)
		{
			printf(" %d", y[i]);
		}
		printf("\n");
		printf("%d", x[1]);
		for (int i = 2; i <= c1; ++i)
		{
			printf(" %d", x[i]);
		}
		printf("\n");
	}
	return 0;
}