zoukankan      html  css  js  c++  java
  • 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) 试一下。

  • 相关阅读:
    搜索二维矩阵 240
    238 除自身以外数组的乘积 左右乘积数组
    160 相交链表
    152乘积最大子数组 dp
    leetcode 739 每日温度 单调栈
    543求二叉树的直径
    IOS 支付相关
    Intellij IDEA--can't use subversion command line client : svn
    每日日报34——通过SQL语句将某个字段的括号给去掉
    每日日报33——VisualStudio2013代码格式化快捷键+给窗体添加按钮
  • 原文地址:https://www.cnblogs.com/last-diary/p/11562080.html
Copyright © 2011-2022 走看看