luogu P1886滑动窗口
Posted last-diary
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu P1886滑动窗口相关的知识,希望对你有一定的参考价值。
\(luogu\ P1886\)滑动窗口
这道题目比较简单,但是因为经常忘记单调队列做滑动窗口所以写博客来加深一下印象。
如果求区间最小值,我们用发现右端点从前往后扫的方法一个数如果有贡献,当且仅当当前扫描的右端点的前面到这个数中间没有比这个数更小的数,因为如果有比这个数更小的数的话,这个更小的数肯定就会成为区间的最小值。如果一个数没有贡献的时候就是区间的左端点比这个数的下标要大的时候。
所以我们用一个双端队列来维护,每次进入队列的时候检查队尾的数如果比要加入得数大的话,就不断弹出队尾,之后我们将这个数压入队尾,然后我们在检查一下队列头的数的下标是否比枚举到的区间左端点大,如果小的话就弹出队头。这样之后答案就是队头的数。
重点是标程。
#include<bits/stdc++.h>
#include<vector>
using std::vector;
const int N=1e6+100;
vector<int>v;
int n,k;
int a[N];
inline int read()
int ans=0,p=1;
char ch=getchar();
while (ch<'0'||ch>'9') if (ch=='-') p=-1;ch=getchar();
while (ch>='0'&&ch<='9') ans=ans*10-'0'+ch;ch=getchar();
return ans*p;
int main()
n=read();k=read();
for (int i=1;i<=n;i++)
a[i]=read();
for (int i=1;i<=n;i++)
while (!v.empty()&&a[v.back()]>a[i]) v.pop_back();
v.push_back(i);
if (!v.empty()&&v.front()<i-k+1) v.erase(v.begin(),v.begin()+1);
if (i>=k) printf("%d ",a[v.front()]);
printf("\n");
v.clear();
for (int i=1;i<=n;i++)
while (!v.empty()&&a[v.back()]<a[i]) v.pop_back();
v.push_back(i);
if (!v.empty()&&v.front()<i-k+1) v.erase(v.begin(),v.begin()+1);
if (i>=k) printf("%d ",a[v.front()]);
return 0;
如果要开多个队列,推荐使用 \(vector\) ,不信可以开 \(10^5\) 个 \(deque\) 和 \(vector\) 试一下。
以上是关于luogu P1886滑动窗口的主要内容,如果未能解决你的问题,请参考以下文章