單調隊列

轉載http://blog.csdn.net/brodrinkwater/article/details/59713954

單調隊列

今天問了長者有關單調隊列的知識,單調隊列這種東西其實用途並不是特別的廣泛,只是在處理區間上詢問的時候比較管用,而且這種詢問有限制,比如:
一個含有n項的數列(n<=2000000),求出每一項前的m個數到它這個區間內的最小值。若前面的數不足m項則從第1個數開始,若前面沒有數則輸出0。
這種類似的題目,每次詢問前m個數中最小的,顯然暴力的話是O(n * m)的每個點枚舉一遍m,就是這樣,但是暴力顯然會TLE,那有什麼辦法呢?
RMQ是可以的,但是有一個問題,就是MLE,2000000 * 20,會炸空間,線段樹顯然是可以的,但是還不是最優的。所以我們引出單調隊列這種東西,解決序列上滑塊的問題(m這個區間在序列上動來動去,就像是個滑塊^_^).

單調隊列?

我們製作一個嚴格上升或下降的隊列,它的隊首是你處理當前區間的最大(最小)值,然後進行刪除和加入的操作。
加入: 我們假設有8,1,2,3,7,9,6.這樣的一個序列,我們想要一個單調上升的序列,這樣就可以保證隊首是最小的。我們加入元素的時候我們要存下每個值在原序列中的下標,因爲,我們只有處理[i-m,i]這樣的一個區間,如果隊首元素的下標不在這個區間,顯然就毫無意義了不。好,我們開始加入元素,我們每次添加元素,從隊尾開始比較,直到找到比它小的數替換掉。
假設沒有刪除操作
第一次 :8
第二次:1(1 < 8 所以 我們替換掉8)
第三次:1,2.
第四次:1,2,3.
第五次:1,2,3,7.
第六次:1,2,3,7,9.
第七次:1,2,3,6.(跟7,9,比較都小,所以替換,尾指針直到6的位置)。

刪除
刪除其實很簡單,我們比較隊首的下標如果不在範圍內直接刪掉。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>

using namespace std;

#define REP(i,a,b) for(register int i = (a), i##_end_ = (b); i <= i##_end_ ; ++i)

inline int read()
{
    char c = getchar();register int fg = 1,sum = 0;
    while(c < '0' || c > '9')
    {
        if(c == '-')fg = -1;
        c = getchar();
    }
    while(c  >= '0' && c <= '9')
    {
        sum =sum * 10 + c - '0';
        c = getchar();
    }
    return fg * sum;
}

const int maxn = 2000000+10;

struct T
{
    int val,pos;
};

struct que
{
    int l,r;
    T a[maxn];
    que(){l = 1, r = 0;}
    inline void putin(T x)//加入
    {
        while(r >= l && a[r].val > x.val)r--;
        a[++r] = x;
    }

    inline void pop(int pos)//刪除
    {
        while(r >= l && a[l].pos < pos)l++;
    }
    void print()
    {
        for(int i=l;i<=r;i++)
            printf("%d ",a[i].val);
        printf("\n");
    }
    inline int top()
        {return a[l].val;}
}q;

int n,m,f[maxn];

int main()
{
    n = read(),m = read();
    REP(i,1,n)f[i] = read();
    puts("0");
    q.putin((T){f[1],1});
    REP(i,2,n)
    {   q.print();
        if(i-m>=0)q.pop(i-m);

        printf("%d\n",q.top());
        q.putin((T){f[i],i});
    }
    return 0;
}


發佈了83 篇原創文章 · 獲贊 27 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章