zoukankan      html  css  js  c++  java
  • 单调队列

    咕咕咕咕的鸽子 MK 来填坑了……

    先看例题:P1886 滑动窗口 /【模板】单调队列

    注:摘要图片为例题中的图片 QwQ。

    emm,建议先看看关于单调栈的博客,便于理解单调队列。

    所以单调队列就是队列内元素具有单调性的队列。而单调队列的用处就是求区间内的最大/最小值。

    那么怎么求呢?以求区间最大值为例,我们不妨让队首为我们要的答案,那么这就是一个单调递减的队列。

    有一句话叫:“如果一个人比你小还比你强,那么你就永远无法超越他了。”什么意思呢?就是说,如果一个元素比你后入队还比你大,你就永远无法成为最大了,那么你就没用了,就可以 退役 出队了。而每次队列新加入的元素肯定是后入队的,所以在入队之前把队尾和这个元素做比较:若比这个元素小(在求最大值的情况下是小),那么就把队尾出队,直到队尾比这个元素大(如果比他大就可能成为最大值)或队列为空,然后把这个元素入队(从队尾)(一定要入队,因为在前面的 退役 出队后你就有机会成为最大了)。

    你以为这样就结束了?NoNoNo!我们还要在每次入队的时候判断队首是否不在这个区间里。这里只要一个if而不是循环,因为每次都这样判断可以保证最多只有一个(也就是队首)不在区间内。

    上代码吧:

    #include<bits/stdc++.h>
    using namespace std;
    int n,k,a[1000005];//原数组
    deque<pair<int,int> >d1;
    deque<pair<int,int> >d2;
    //d1,d2分别为求最大值,最小值的单调队列,队列里的第一个关键字存储值,第二个关键字存储这个元素在a[]数组中的位置(下标)
    queue<int>qmin;
    queue<int>qmax;
    //由于后面是一起做的,所以用队列存储答案(当然可以用数组)
    int main()
    {
    	cin>>n>>k;
    	for(register int i=1;i<=n;i++) cin>>a[i];//读入元素
    	for(register int i=1;i<k;i++)
    	{
        		while(!d1.empty()&&d1.back().first<a[i]) d1.pop_back();
    		while(!d2.empty()&&d2.back().first>a[i]) d2.pop_back();
    		d1.push_back(make_pair(a[i],i));
    		d2.push_back(make_pair(a[i],i));
    	}//先把前k-1个入队
    	if(k==1)//见后面的while,发现需要特判k=1的情况
    	{
    		d1.push_back(make_pair(a[1],1));
    		d2.push_back(make_pair(a[1],1));
    		qmin.push(a[1]);
    		qmax.push(a[1]);
    	}
    	while(d1.back().second<n)//表示后面还有元素
    	{
    		int xx1=a[d1.back().second+1],yy1=d1.back().second+1;
    		int xx2=a[d2.back().second+1],yy2=d2.back().second+1;
            	//分别记录两个单调队列的队尾的元素大小和在a[]里的序号
    		while(!d1.empty()&&d1.back().first<xx1) d1.pop_back();
    		while(!d2.empty()&&d2.back().first>xx2) d2.pop_back();
            	//让那些又老又弱的元素出队
    		if(!d1.empty()&&d1.front().second<yy1-k+1) d1.pop_front();
    		if(!d2.empty()&&d2.front().second<yy2-k+1) d2.pop_front();
            	//让不在区间内的元素出队
    		d1.push_back(make_pair(xx1,yy1));
    		d2.push_back(make_pair(xx2,yy2));
            	//将新元素入队
    		qmin.push(d1.front().first);
    		qmax.push(d2.front().first);
            	//存储答案
    	}
    	while(!qmax.empty())
    	{
    		cout<<qmax.front()<<' ';
    		qmax.pop();
    	}
    	cout<<'
    ';
    	while(!qmin.empty())
    	{
    		cout<<qmin.front()<<' ';
    		qmin.pop();
    	}
        	//输出答案
    	return 0;
    }
    
  • 相关阅读:
    使用vim + cscope/ctags
    python类库32[序列化和反序列化之pickle]
    Perforce2012新特征=20个用户免费+云
    Linux进程的uid和euid
    perl安装模块到自己的home ( install perl module without root)
    Python分布式+云计算
    Linux命令xargs+cut
    python实例32[简单的HttpServer]
    Python转载[编码规范]
    Linux命令lsof
  • 原文地址:https://www.cnblogs.com/mk-oi/p/13610513.html
Copyright © 2011-2022 走看看