<8/11>集训日记

整理一下单调队列的内容。

定义:队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。

单调队列的常用操作如下:

1)插入:若新元素从队尾插入后会破坏单调性,则删除队尾元素,直到插入后不再破坏单调性为止,再将其插入单调队列。

2)获取最优(最大、最小)值:访问首尾元素


单调队列一道入门级题目,滑动窗口中元素的最值[POJ2823]

题目大意:给定一个大小已知的数组以及一个大小已知的滑动窗口,窗口每个时刻向后移动一位,求出每个时刻窗口中数字的最大值和最小值。

分析:区间长度为k,求区间内的最大值时,考虑第i个数和第j个数,j-i<k,若a[i]<a[j],那么a[i]将毫无用处。因为窗口的移动,a[i]要比a[j]先移出去,无论如何,区间的最大值都不可能是a[i]。这样,考虑构造一个单调递增的队列,存放相应的序号,当a[队尾]>=要入队数据a[i],删除队尾元素;当队头<=i-k时,删除队头元素。

代码及注释如下:

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int N = 1100000;

int n,k;

int a[N];

int DanDiao_Que[N]; //单调递减队列(最大),单调递增队列(最小)

int head,tail;//队首队尾

void Min()//递增

{

   int i;

   int head = 1;

   int tail = 0;

   for(i = 0; i < k-1; i++)//开始的k

    {

       while(head<=tail && a[DanDiao_Que[tail]]>=a[i]) tail--;

       tail++;

       DanDiao_Que[tail] = i;

    }

   for(i = k-1; i < n; i++)//移动中的区间

    {

       while(head<=tail && a[DanDiao_Que[tail]]>=a[i]) tail--;

       tail++;

       DanDiao_Que[tail] = i;

       while(DanDiao_Que[head]< i-k+1) head++;//没到结尾处

       printf("%d",a[DanDiao_Que[head]]);//单增的队首即为最小值

       printf("%c",i==n-1?'\n':' ');//空格及回车

    }

}

void Max()//递减

{

   int i;

   int head = 1;

   int tail = 0;

   for(i = 0; i < k-1; i++)

    {

       while(head<=tail && a[DanDiao_Que[tail]]<=a[i]) tail--;

       tail++;

       DanDiao_Que[tail] = i;

    }

   for(i = k-1; i < n; i++)

    {

       while(head<=tail && a[DanDiao_Que[tail]]<=a[i]) tail--;

       tail++;

       DanDiao_Que[tail] = i;

       while(DanDiao_Que[head]< i-k+1) head++;

       printf("%d",a[DanDiao_Que[head]]);//单减的队首即为最大值

       printf("%c",i==n-1?'\n':' ');

    }

}

 

int main()

{

   scanf("%d %d",&n,&k);//n个数 区间长度k

   for(int i = 0 ;i < n; i++)

       scanf("%d",&a[i]);//n个数

   Min();

   Max();

   return 0;

}

 看了一些树状数组的课件,有点儿懵,继续理解吧。

以上~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值