uestc oj 1221 Sliding Window

 

  Sliding Window    http://www.acm.uestc.edu.cn/problem.php?pid=1221


  本题运用单调队列解决。
  由于需要输出最大值与最小值两个序列 ,于是需要维护两个分别是递增的和递减的单调队列。
  建立一个队列数组,数组元素是一个结构体,结构体的id信息用于保存这个队列元素在原数组中的坐标(主要作用在于比较对头元素是否符合要求。我曾经想在队列中直接保存数值)但是苦于无法获得head的id,因为它时刻的变动。
  首先将队列的首元素的id写成0,然后从1开始逐个加入逐个记录,维护递增队列的时候将逐个入队的元素与队尾的元素进行比较,如果大于队尾元素则替换队尾元素直到小于队尾元素,然后将其赋给队尾元素,再检查队头,如果对头元素与队尾元素之间的距离大于k,则head++,再将对头元素赋给相应位置的max[i]min[i].
  注意输出的时候最后一个元素不能带空格。



#include<cstdio>
#define N 1000005
using namespace std;

struct node
{
    int id;
};
node queue[N];
int s[N],max[N],min[N];
int a,k,tail,head;

//递减队列  求取最大值
void dec()
{
  head = tail =0;
  queue[tail++].id=0;
  max[0] = s[0];
  for(int i=1;i<a;i++)
  {
      while(s[queue[tail-1].id]<s[i]&&head<tail)
      {
          tail--;
      }
      queue[tail++].id =i;
      //去除多余的对头元素
      if(queue[head].id<i-k+1)
      head++;
      max[i] = s[queue[head].id];
  }
}

//递增队列 求取最小值
void inc()
{
  head = tail =0;
  queue[tail++].id=0;
  min[0] = s[0];
  for(int i=1;i<a;i++)
  {
      while(s[queue[tail-1].id]>s[i]&&head<tail)
      {
          tail--;
      }
      queue[tail++].id =i;
      //去除多余的对头元素
      if(queue[head].id<i-k+1)
      head++;
      min[i] = s[queue[head].id];
  }
}


int main()
{
    //freopen("1.txt","r",stdin);
    while(scanf("%d%d",&a,&k)==2)
    {
        int i;
        for(i=0;i<a;i++)
        scanf("%d",&s[i]);
        dec();
        inc();

        for(i=k-1;i<a-1;i++)
        printf("%d ",min[i]);
        printf("%d\n",min[i]);
        for(i=k-1;i<a-1;i++)
        printf("%d ",max[i]);
        printf("%d",max[i]);
    }
    return 0;
}



至于为什么要使用单调队列,当然是因为省时间,效率高。
如果采用暴力的解法解答这个题目的话,就会出现超时。
显然这个题目如果暴力的话需要O(n^2)的时间复杂度(两个for循环)

你可能感兴趣的:(单调队列)