【POJ2823】Sliding Window

http://poj.org/problem?id=2823

题意:你有一个长度n的序列,分别询问[1,k],[2,k+1],[3,k+2],...,[n-k+1,n]这n-k+1个区间的最大值和最小值。

单调队列入门题。用两个单调队列分别维护当前最大值和最小值的最优解、次优解、……K优解。

每次拓展一个数就不断将队尾的劣解出队,保持队列的单调性。然后不断将队首的过气解(即距离当前位置大于等于k)出队。之后队列的队首就是最优解了。

#include <iostream>
#include <deque>
#define maxn 1000005
using namespace std;
int n, k, a[maxn];
deque<int> mx, mn; // 分别存最大值的最优解和最小值的最优解
int mxans[maxn], mnans[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> k;
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i < k; i++) // 先处理前k-1个数
    {
        // 将队尾的劣解出队
        while (!mn.empty() && a[mn.back()] > a[i])
            mn.pop_back();
        mn.push_back(i);
        while (!mx.empty() && a[mx.back()] < a[i])
            mx.pop_back();
        mx.push_back(i); // 插入当前解
    }
    for (int i = k; i <= n; i++)
    {
        // 将队尾的劣解出队
        while (!mn.empty() && a[mn.back()] > a[i])
            mn.pop_back();
        mn.push_back(i);
        while (!mx.empty() && a[mx.back()] < a[i])
            mx.pop_back();
        mx.push_back(i);

        // 将队首的过气解出队
        while (!mx.empty() && i - mx.front() >= k)
            mx.pop_front();
        while (!mn.empty() && i - mn.front() >= k)
            mn.pop_front();

        mxans[i] = mx.front();
        mnans[i] = mn.front();
    }
    for (int i = k; i <= n; i++)
        cout << a[mnans[i]] << ' ';
    cout << endl;
    for (int i = k; i <= n; i++)
        cout << a[mxans[i]] << ' ';
    cout << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/ssttkkl/p/7625920.html