P1886 滑动窗口
单调队列双倍经验系列。。
这道题就是所谓的滑动窗口问题。
我们对于最大值询问,就维护一个单调递减的单调队列,队头就是最优解。
最小值同理。
注意:在队列中我们要传入每个元素进入的时间,这样才能实时从队头弹出元素,才不会WA。
有一个坑点:当\(k=1\)时,不能对第一个元素进行特殊处理。好坑啊。。。
代码:
#include<cstdio>
#include<queue>
const int maxn = 1e6 + 5;
struct Nodes
{
int tim, val;
};
std::deque<Nodes> q;
int a[maxn], n, k;
int read()
{
int ans = 0, s = 1;
char ch = getchar();
while(ch > '9' || ch < '0')
{
if(ch == '-') s = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
ans = ans * 10 + ch - '0';
ch = getchar();
}
return s * ans;
}
int main()
{
//freopen("testdata.in", "r", stdin);
//freopen("out.txt", "w", stdout);
n = read(), k = read();
for(int i = 1; i <= n; i++) a[i] = read();
//q.push_back((Nodes){1, a[1]});
for(int i = 1; i <= n; i++)
{
while(!q.empty() && a[i] < q.back().val) q.pop_back();
q.push_back((Nodes){i, a[i]});
if(q.front().tim + k <= i) q.pop_front();
if(i >= k) printf("%d ", q.front().val);
}
printf("\n");
q.clear();
//q.push_back((Nodes){1, a[1]});
for(int i = 1; i <= n; i++)
{
while(!q.empty() && a[i] > q.back().val) q.pop_back();
q.push_back((Nodes){i, a[i]});
if(q.front().tim + k <= i) q.pop_front();
if(i >= k) printf("%d ", q.front().val);
}
printf("\n");
return 0;
}