单调队列

112 阅读1分钟

介绍

常常被用来解决互不包含的最值问题。什么是互不包含的区间?[1, 5]包含[2, 3],但不包含[1, 3]或者[3, 4]。时间复杂度O(n+q)O(n+q),即数组长度加询问次数。

代码介绍

以P1886为例。对于原数组a,创建一个新的数组q,并在q上形成单调队列,以b和f来表示单调队列的开头和结尾。

int n,k;

int a[1000005], q[1000005];

int main(int argc, const char  argv[]){

    cin>>n>>k;

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

        cin>>a[i];

    }

    int f = 0;

    int b = 0;
    
    return 0;
}

接下来每次在a数组中读入一个数字,都需要更新单调队列。如果是要求最小值,则需使单调队列为严格递增。对于队尾来说,如果有比新读入的数小的数,则需要删去那些数,再把读入的数排到末尾。对于队首来说,如果已经没有用了,不在题目询问的区间之中,也需要删去。

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

        while(b < f && a[i] <= a[q[f-1]]){

            f--;

        }//删去队尾的数

        q[f++] = i;//加入队尾

        while(i-k >= q[b]){

            b++;

        }//删去队首过时的数

        if(i >= k-1){

            cout<<a[q[b]];

            if(i == n-1){

                cout<<endl;

            }

            else{

                cout<<" ";

            }

        }

    }

注意,单调队列中存储的是下标,并且队列可以没有重复的数字。