POJ 2823 Sliding Window(单调队列)

题目链接:http://poj.org/problem?id=2823

题意:给出一个长度为n的数组 a ,滑窗大小为k。滑窗每个时刻往后滑动一个,求出每个时刻窗中最大值和最小值。

思路:此为单调队列入门题。

单调队列保持如下两个性质

  1. 队中保持对某一个优先级保持单调(严格?)。
  2. 队中的元素从队首到队尾保证时刻递增(非依次递增),即队首的元素先过期,队尾元素为新入队的元素。

维护

  1. 入队:保持新元素在队尾,所以新元素从队尾开始依次比较,直至满足条件,对于不满足条件的原本在队中的元素直接抛弃即可(因为新元素相比于那些删除的元素更优,且删除的元素更旧,所以删除的元素不会在之后的查询中成为答案)。
  2. 出队:直接取队首元素即可,即保持了队首元素先过期。

复杂度:每个元素入队出队均只有一次,所以复杂度为O(n)。

此题维护两个单调队列用来求最大值和最小值即可。

代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

const int N = 1e6 + 10;

struct Node {
  int v;
  int p;

  Node() {}

  Node(int a, int b) {
    v = a;
    p = b;
  }

};

Node que[2][N];

struct Que {
  int head, tail;

  Que() {
    head = 0;
    tail = 0;
  }

  bool cmp(int t, int a, int b) {
    if (t)
      return a >= b;
    else
      return a <= b;
  }

  void in(int x, int t, int v, int p) {
    while (head < tail && cmp(t, v, que[x][tail - 1].v))
      tail--;
    que[x][tail++] = Node(v, p);
  }

  Node out(int x) {
    return que[x][head];
  }

  void pop(int x, int i, int w) {
    while (head < tail && i - que[x][head].p >= w)
      head++;
  }

};

int n, k;

int main() {
  while (scanf("%d%d", &n, &k) != EOF) {
    Que Max, Min;
    int cur = 0;
    int b[N], c[N];
    int x;
    for (int i = 0; i < k; i++) {
      scanf("%d", &x);
      Max.in(0, 1, x, i);
      Min.in(1, 0, x, i);
    }
    for (int i = k; i <= n; i++) {
      b[cur] = Max.out(0).v;
      c[cur++] = Min.out(1).v;
      if (i == n)
        break;
      scanf("%d", &x);
      Max.pop(0, i, k);
      Max.in(0, 1, x, i);
      Min.pop(1, i, k);
      Min.in(1, 0, x, i);
    }
    for (int i = 0; i < cur; i++) {
      if (i)
        printf(" ");
      printf("%d", c[i]);
    }
    printf("\n");
    for (int i = 0; i < cur; i++) {
      if (i)
        printf(" ");
      printf("%d", b[i]);
    }
    printf("\n");
  }
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值