單調隊列——求m區間內的最小值
阿新 • • 發佈:2017-06-18
microsoft n) 入隊和出隊 mes %d 序列 數組 lan mic
單調隊列,顧名思義是指隊列內的元素是有序的,隊頭為當前的最大值(單調遞減隊列)或最小值(單調遞增序列),以單調遞減隊列為例來看隊列的入隊和出隊操作:
1、入隊:
如果當前元素要進隊,把當前元素和隊尾元素比較,如果當前元素小於隊尾元素,那麽當前元素直接進隊,如果當前元素大於隊尾元素,那麽隊尾出隊,將當前元素和新的隊尾再做比較,直到當前元素大於隊尾元素或者隊列為空。單調隊列只能在隊尾插入元素,隊尾和隊頭都可以刪除元素。
2、出隊:
出隊直接取隊頭即可,因為用單調隊列就是為了取最值,而隊頭就是最值。
例子:將數組a[] = {3, 5, 2, 8, 1, 4, 7}依次入隊,並保證隊列為一個 單調遞減 隊列。
- 3入隊,隊列為空直接入隊,隊列元素為:3;
- 5入隊,5和隊尾比較,5大於3,3出隊,隊為空,5入隊,隊列元素為:5;
- 2入隊,2和隊尾比較,2小於5,直接入隊,隊列元素為:5,2;
- 8入隊,8和隊尾比較,2出隊,8再和隊尾比較,5出隊,隊為空,8入隊,隊列元素為:8;
- 1入隊,...,隊列元素為:8,1;
- 4入隊,...,隊列元素為:8,4;
- 7入隊,...,隊列元素為:8,7。
- i = 0,初始隊列為空,7入隊,隊列為:{ 0(7) }, (0為下標,括號為下標對應的值) ,窗口區間為[0],最大值為隊頭a[0] = 7;
- i = 1,隊頭下標沒有超出k, 3入隊,隊列為:{ 0(7), 1(3) },窗口區間為[0,1],最大值為隊頭a[0] = 7;
- i = 2,隊頭下標沒有超出k,2入隊,隊列為:{ 0{7), 1(3), 2(2) },窗口區間為[0,1,2],最大值為隊頭a[0] = 7;
- i = 3,隊頭下標為0超出k,刪除隊頭,5入隊,隊列為:{ 3(5) },窗口區間為[1,2,3],最大值為隊頭a[3] = 5;
- i = 4,隊頭下標沒有超出k,6入隊,隊列為:{ 4(6) },窗口區間為[2, 3, 4],最大值為隊頭a[4] = 6;
- 窗口繼續向右滑動,如果當前隊頭下標超出範圍就刪除隊頭,然後去隊頭,沒有超出範圍就直接取隊頭。
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,a[2000010];
int q[2000010],h=1,t=1;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
printf("0\n");
q[1]=1;
for(int i=2;i<=n;i++)
{
printf("%d\n",a[q[h]]);
if(q[h]<=i-m)
h++;
while(a[i]<=a[q[t]]&&t>=h)
t--;
t++;
q[t]=i;
}
return 0;
}
單調隊列——求m區間內的最小值