0
点赞
收藏
分享

微信扫一扫

初谈单调队列...POJ 2823


   前几天做过这题...当时使用线段树做的....要跑9500MS才能过...今天看了下单调队列...以为很难...但理解一下..发现单调队列其实很简单..

   单调队列是从数列前扫到数列后...维护一个最值或者一个所需的最优解之类的...每次的最优解都是在队列的头....所以要一直维护队列..使其从头到尾都是单调的..要能保证如果当前头要出去了...后面的元素能马上顶上来作为头...

   就拿POJ2823来举例....题目要求是给了一串n个数...从左到右每次框k个连续数..问每次框的数中最大数和最小数是什么..样例输入输出:


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

  

   就拿样例说....准备一个队列...Myqueue...h代表队列头( 里面存的是下标不是数..为了是判断队首出列)..p代表队列尾..初始值h=1,p=0...就拿每次要一段最小值的队列变化过程来描述一下:

  1、插入第1个数    Myqueue = { 1 }  h=1;  p=1  小于所给的框..还不需输出

  2、插入第2个数    Myqueue= { 1 2 } h=1; p=2    (  因为2号元素比1号元素大...先排到后面 )   小于所给的框..还不需输出

输出 a[ Myqueue[h] ]的值 -1

输出 a[ Myqueue[h] ]的值 -3

输出 a[ Myqueue[h] ]的值 -3

输出 a[ Myqueue[h] ]的值 -3

这里为什么4出列了?因为4到7已经不能被所给的范围框住了...所以4要出列..然后继续操作...因为7号元素比6号元素大...先排到后面)   输出 a[ Myqueue[h] ]的值 3

输出 a[ Myqueue[h] ]的值 3


    还有一点要特别注意!!!如果后面的数和h[p]元素的数相等时...也要挤掉h[p]的....因为这个我WA了一次...囧....

   这道题用单调队列来跑只要5000MS..的确快了不少..但看大牛们还能更快...想知道怎么做到的...


每次插入新数到队列都要从队尾往队首扫..扫到比自己小的就确定位置..扫到比自大的就把这个大的数给挤掉.....如果从前往后扫....例如

   1 2 3 4 5 6 7 8  9 ..... 很长一列...要插入一个很大的数...从前一直遍历到最后面..才确定位置..这不是关键..关键是这一路过去..什么操作都没有做..白白扫了一大片空间...而从后往前扫...要么确定位置...要么踢到元素...总是在操作..所以必须要从后往前来判断并插入.... 


Program :

/*
POJ2823 - 单调队列
*/
#include<iostream>
using namespace std;
int n,m,a[1000001],Myqueue[1000001];
void MinQueue()
{
int p=0,h=1,k,i;
Myqueue[1]=1;
for (k=1;k<=n;k++)
{
if (k-Myqueue[h]==m) h++;
if (p==h-1 || a[k]>a[Myqueue[p]]){ p++; Myqueue[p]=k; }
else
{
while (p>=h && a[k]<=a[Myqueue[p]]) { Myqueue[p]=k; p--; }
p++;
}
if (k>=m) printf("%d ",a[Myqueue[h]]);
}
printf("\n");
}
void MaxQueue()
{
int p=0,h=1,k,i; Myqueue[1]=1;
for (k=1;k<=n;k++)
{
if (k-Myqueue[h]==m) h++;
if (p==h-1 || a[k]<a[Myqueue[p]]){ p++; Myqueue[p]=k; }
else
{
while (p>=h && a[k]>=a[Myqueue[p]]) { Myqueue[p]=k; p--; }
p++;
}
if (k>=m) printf("%d ",a[Myqueue[h]]);
}
printf("\n");
}
int main()
{
freopen("2823.in","r",stdin);
freopen("2823T.out","w",stdout);
scanf("%d%d",&n,&m);
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
MinQueue();
MaxQueue();
return 0;
}



举报

相关推荐

0 条评论