zoukankan      html  css  js  c++  java
  • 洛谷 P1886 滑动窗口 /【模板】单调队列

    题目传送门

    普及算法都不会,参加个锤子CSP—S

    思路

    完全剽窃别人的思路,话说回来,我要是会还学它干啥。单调队列,顾名思义,队列里的元素都是有单调性的,通过维护单调性,优化时间复杂度。干说其实根本没用,直接看题。首先根据题解的思路,求最小值的时候将队列内元素从小到大排列,这样每次查询最小值的时候,只需要弹出队首即可。然后我们考虑怎么样维护单调队列。当来了一个新数,我们就从后往前找(就是从大到小),如果这个新数比队列中的那些元素都大,那么那些大的元素就已经不可能作为最小值的候选人了,所以直接弹出队列即可。每次循环还要检查一遍队列的跨度,如果队首和当前的序号相差过远了,那么就只好忍痛割爱,弹出最小的元素了。不难发现,普通的队列是无法实现单调队列的(我不会告诉你我想了一个小时才发现了这个道理),因为它既要弹出队首元素也要弹出队尾元素,这就需要手写一个双端队列来实现。其实并不难写,就是队尾也可以弹出元素罢了。但是代码实现还是有一些细节的。

    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstdlib>
    #include<ctime>
    #include<cstring>
    #include<queue>
    using namespace std;
    typedef long long ll;
    int n,m;
    ll a[1000005];
    int q[1000005],p[1000005];
    void _minn(){
    	int head=1,tail=0;//这样初始化,是因为队列内一开始是空的,而队列为空时就相当于是head>tail
    	for(int i=1;i<=n;i++){
    		while(head<=tail&&q[tail]>=a[i]){//维护单调性
    			tail--;
    		}
    		q[++tail]=a[i];
    		p[tail]=i;
    		if(p[head]<=i-m) head++;//“窗口”长度过长,被迫抛弃最小元素(如果将这一行加到while循环前面的话,则需要加上head<=tail这一个条件。否则的话若区间长度为1,则第一次循环后head=2,tail=0,喜提RE)
    		if(i>=m) printf("%lld ",a[p[head]]);
    	}
    	printf("
    ");
    }
    void _maxx(){
    	int head=1,tail=0;
    	for(int i=1;i<=n;i++){
    		while(head<=tail&&q[tail]<=a[i]){
    			tail--;
    		}
    		q[++tail]=a[i];
    		p[tail]=i;
    		if(p[head]<=i-m) head++;
    		if(i>=m) printf("%lld ",a[p[head]]);
    	}
    	printf("
    ");
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++){
    		scanf("%lld",&a[i]);
    	}
    	_minn();
    	_maxx();
    	return 0;
    }
    
  • 相关阅读:
    python获取当前路径
    python的StringIO
    python判断两个文件是否相同
    Linux查找文件内容
    python日志syslog运用
    python获取当前运行程序的名字
    python连接Linux命令行
    python预编译函数compile,exec,eval
    python日志模块
    Scala安装教程
  • 原文地址:https://www.cnblogs.com/57xmz/p/13928686.html
Copyright © 2011-2022 走看看