咕咕咕咕的鸽子 MK 来填坑了……html
先看例题:P1886 滑动窗口 /【模板】单调队列c++
注:摘要图片为例题中的图片 QwQ。数组
emm,建议先看看关于单调栈的博客,便于理解单调队列。spa
因此单调队列就是队列内元素具备单调性的队列。而单调队列的用处就是求区间内的最大/最小值。code
那么怎么求呢?以求区间最大值为例,咱们不妨让队首为咱们要的答案,那么这就是一个单调递减的队列。htm
有一句话叫:“若是一我的比你小还比你强,那么你就永远没法超越他了。”什么意思呢?就是说,若是一个元素比你后入队还比你大,你就永远没法成为最大了,那么你就没用了,就能够 退役 出队了。而每次队列新加入的元素确定是后入队的,因此在入队以前把队尾和这个元素作比较:若比这个元素小(在求最大值的状况下是小),那么就把队尾出队,直到队尾比这个元素大(若是比他大就可能成为最大值)或队列为空,而后把这个元素入队(从队尾)(必定要入队,由于在前面的 退役 出队后你就有机会成为最大了)。blog
你觉得这样就结束了?NoNoNo!咱们还要在每次入队的时候判断队首是否不在这个区间里。这里只要一个if
而不是循环,由于每次都这样判断能够保证最多只有一个(也就是队首)不在区间内。队列
上代码吧:图片
#include<bits/stdc++.h> using namespace std; int n,k,a[1000005];//原数组 deque<pair<int,int> >d1; deque<pair<int,int> >d2; //d1,d2分别为求最大值,最小值的单调队列,队列里的第一个关键字存储值,第二个关键字存储这个元素在a[]数组中的位置(下标) queue<int>qmin; queue<int>qmax; //因为后面是一块儿作的,因此用队列存储答案(固然能够用数组) int main() { cin>>n>>k; for(register int i=1;i<=n;i++) cin>>a[i];//读入元素 for(register int i=1;i<k;i++) { while(!d1.empty()&&d1.back().first<a[i]) d1.pop_back(); while(!d2.empty()&&d2.back().first>a[i]) d2.pop_back(); d1.push_back(make_pair(a[i],i)); d2.push_back(make_pair(a[i],i)); }//先把前k-1个入队 if(k==1)//见后面的while,发现须要特判k=1的状况 { d1.push_back(make_pair(a[1],1)); d2.push_back(make_pair(a[1],1)); qmin.push(a[1]); qmax.push(a[1]); } while(d1.back().second<n)//表示后面还有元素 { int xx1=a[d1.back().second+1],yy1=d1.back().second+1; int xx2=a[d2.back().second+1],yy2=d2.back().second+1; //分别记录两个单调队列的队尾的元素大小和在a[]里的序号 while(!d1.empty()&&d1.back().first<xx1) d1.pop_back(); while(!d2.empty()&&d2.back().first>xx2) d2.pop_back(); //让那些又老又弱的元素出队 if(!d1.empty()&&d1.front().second<yy1-k+1) d1.pop_front(); if(!d2.empty()&&d2.front().second<yy2-k+1) d2.pop_front(); //让不在区间内的元素出队 d1.push_back(make_pair(xx1,yy1)); d2.push_back(make_pair(xx2,yy2)); //将新元素入队 qmin.push(d1.front().first); qmax.push(d2.front().first); //存储答案 } while(!qmax.empty()) { cout<<qmax.front()<<' '; qmax.pop(); } cout<<'\n'; while(!qmin.empty()) { cout<<qmin.front()<<' '; qmin.pop(); } //输出答案 return 0; }