• 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("
    ");
    	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) 试一下。

  • 相关阅读:
    常用的dos命令
    java环境的配置
    javascript面向对象个人理解
    js如何获取样式?
    springboot新建项目遇到Whitelabel Error Page
    CSS 隐藏页面元素的 几 种方法总结
    优美动听的葫芦丝名曲
    大前端资料合集
    CSS实现背景透明,文字不透明(兼容所有浏览器)
    文字上下无缝滚动效果
  • 原文地址:https://www.cnblogs.com/last-diary/p/11562080.html
Copyright © 2020-2023  润新知