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) 试一下。

  • 相关阅读:
    sublime去除空白行和重复行
    python list删除数据 和复制 列表
    微博实现简繁体转换
    2017.10.27日面试总结
    python 类和__class__理解
    python 单例模式应用
    pt-query-digest 慢日志监控
    在线安全清空慢查询日志slowlog
    Linux高级系统恢复技术
    灾备演练
  • 原文地址:https://www.cnblogs.com/last-diary/p/11562080.html
Copyright © 2011-2022 走看看