題目鏈接:
1. Window:
2.滑動窗口 /【模板】單調隊列:
題目
給你一個長度爲的數組,一個長爲的滑動的窗體從最左移至最右端,你只能見到窗口的個數,每次窗體向右移動一位,如下表:
你的任務是找出窗口在各位置時的
輸入
第行 , , 第行爲長度爲的數組,每個數:
輸出
行,第行每個位置的,第行每個位置的
數據範圍
數據範圍:
題目
有一個長爲 的序列 ,以及一個大小爲 的窗口。現在這個從左邊開始向右滑動,每次滑動一個單位,求出每次滑動後窗口中的最大值和最小值。
例如:
輸入
輸入一共有兩行,第一行有兩個正整數 。 第二行 個整數,表示序列
輸出
輸出共兩行,第一行爲每次窗口滑動的最小值
第二行爲每次窗口滑動的最大值
樣例輸入
8 3
1 3 -1 -3 5 3 6 7
樣例輸出
-1 -3 -3 -3 3 3
3 3 5 5 6 7
數據範圍
對於 的數據,;
對於 的數據,,。
思路
這道題就是一道單調隊列。
我們先要去輸出最小的,就我們就維護一個從小到大的數組,每次都插入當前的那個數,然後把在它前面比它大的數給踢掉。(因爲要插入這個數而且又要維護數組從小到大)然後我們在踢出一個數,這時候不是踢出數組中的數,而是要看踢出的數是不是數組中的第一個數(因爲這個數可能在讀入的時候就被踢掉了)
而我們要輸出最大的,就是和輸出最小的相反的就是了。
(即從小變大變成從大變小,踢掉比它大的變成踢掉比它小的)
(要用)
代碼
#include<cstdio>
#define ll long long
using namespace std;
struct node {
ll num, x;
}f[1000001];
ll n, k, a[1000001], h, t;
int main() {
scanf("%lld %lld", &n, &k);//讀入
for (int i = 1; i <= n; i++)
scanf("%lld", &a[i]);//讀入
h = 1;//初始化
t = 0;
for (ll i = 1; i <= n; i++) {
while (a[i] <= f[t].x && t >= h) t--;//維護從小到大的數組
f[++t] = (node){i, a[i]};//插入
if (i >= k) {
while (h <= t && f[h].num + k - 1 < i) h++;//踢出隊列
printf("%d ", f[h].x);//輸出
}
}
putchar('\n');
h = 1;//初始化
t = 0;
for (ll i = 1; i <= n; i++) {
while (a[i] >= f[t].x && t >= h) t--;//維護從大到小的數組
f[++t] = (node){i, a[i]};//插入
if (i >= k) {
while (h <= t && f[h].num + k - 1 < i) h++;//踢出隊列
printf("%d ", f[h].x);//輸出
}
}
return 0;
}