poj2823(单调队列)

Sliding Window
Time Limit: 12000MS   Memory Limit: 65536K
Total Submissions: 32200   Accepted: 9566
Case Time Limit: 5000MS

Description

An array of size n ≤ 10 6 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

POJ Monthly--2006.04.28, Ikki
 
本题给定一个整数序列和一个滑动长度k,要求当区间从左到右滑动时区间的嘴直查询,典型的RMQ。
本题要维护一个滑动的区间的最值,线段树失效。直接暴力又会超时。仔细想想可以考虑单调队列。
直接套用别人的解释:

一、 什么是单调(双端)队列
单调队列,顾名思义,就是一个元素单调的队列,那么就能保证队首的元素是最小(最大)的,从而满足动态规划的最优性问题的需求。
单调队列,又名双端队列。双端队列,就是说它不同于一般的队列只能在队首删除、队尾插入,它能够在队首、队尾同时进行删除。
【单调队列的性质】
一般,在动态规划的过程中,单调队列中每个元素一般存储的是两个值:
1、在原数列中的位置(下标)
2、 他在动态规划中的状态值
而单调队列则保证这两个值同时单调。
从以上看,单调队列的元素最好用一个类来放,不这样的话,就要开两个数组。。。

单调队列:单调队列 即保持队列中的元素单调递增(或递减)的这样一个队列,可以从两头删除,只能从队尾插入。单调队列的具体作用在于,由于保持队列中的元素满足单调性,对手元素便是极小值(极大值)了。

 
 
先将前k个元素处理,在处理后面的,单增队列维护最小值,并用下标控制区间长度。时间复杂度为O(N*log(N))
#include<iostream>
#include<cstdio>
using namespace std;

const int MAXN=1000000+10;
int da[MAXN],Inc[MAXN],Dec[MAXN];
int n,k,front1,rear1,front2,rear2;
struct node
{
	int Min,Max;
};

//维护双端单调队列
void Queue()
{
	front1=0,rear1=-1,front2=0,rear2=-1;
	int i,ans=0,start=0;
	node tmp;
	for(i=0;i<k;i++)
	{
		while(front1<=rear1&&da[Dec[rear1]]<=da[i])//保证Dec队列在start-i区间内的递减
			rear1--;
		Dec[++rear1]=i;

		while(front2<=rear2&&da[Inc[rear2]]>=da[i])//保证inc队列在start-i区间内的递增
			rear2--;
		Inc[++rear2]=i;
	}

	printf("%d ",da[Inc[front2]]);
	for(;i<n;i++)
	{
		while(front2<=rear2&&da[Inc[rear2]]>=da[i])//保证inc队列在start-i区间内的递增
			rear2--;
		Inc[++rear2]=i;
		while(Inc[front2]<=i-k)//下标控制区间长度
			front2++;
		if(i!=n-1)
			printf("%d ",da[Inc[front2]]);
	}	
	printf("%d\n",da[Inc[front2]]);

	printf("%d ",da[Dec[front1]]);
	for(i=k;i<n;i++)
	{
		while(front1<=rear1&&da[Dec[rear1]]<=da[i])//保证inc队列在start-i区间内的递增
			rear1--;
		Dec[++rear1]=i;
		while(Dec[front1]<=i-k)//下标控制区间长度
			front1++;
		if(i!=n-1)
			printf("%d ",da[Dec[front1]]);
	}	
	printf("%d\n",da[Dec[front1]]);
}


int main()
{
	int i;
	while(~scanf("%d%d",&n,&k))
	{
		for(i=0;i<n;i++)
			scanf("%d",&da[i]);
		Queue();
	}
	return 0;
}

你可能感兴趣的:(数据结构)