单调队列与单调栈(入门)

这些知识总算啃掉了...

重要的思路就是加入栈和队列时还要加入元素的坐标位置。

使用单调栈可以找到元素向左遍历第一个比他小的元素,也可以找到元素向左遍历第一个比他大的元素。

单调栈就简单点,只有栈顶可以操作,若要找到从左到右第一个比i大的数,就保证严格递减,这样如果到第一个比i大的数是i就会被弹出,总之就是找什么条件的数,第i个数被弹出栈的条件就是什么,建议手打栈,代码如下:

n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    for(int i=1;i<=n;i++)
    {
        while(top>=1&&a[i]>=q[top].s) ans=ans+i-q[top--].id-1;
        q[++top].id=i;q[top].s=a[i]; 
    }
    for(int i=top;i>=1;i--) ans=ans+n-q[top--].id;

单调队列除了tail需要更新,还需要更新head,也就是及时把不符合信息的head出队,、

单调队列性质:

  • 1、维护区间最值
  • 2、去除冗杂状态 如上题,区间中的两个元素a[i],a[j](假设现在再求最大值)
    若 j>i且a[j]>=a[i] ,a[j]比a[i]还大而且还在后面(目前a[j]留在队列肯定比a[i]有用,因为你是往后推, 核心思想 !
  • 其中第二条对动态规划仍使用...

与题目联系时,记得把要求的元素放在队头就行了.

例:

for(int i=1;i<=k;i++)
    {
        while(head<=tail&&q[tail].s>=a[i]) tail--;
        q[++tail].id=i,q[tail].s=a[i];
    }
    mn[++o]=q[head].s;
    for(int i=k+1;i<=n;i++)
    {
        while(head<=tail&&q[tail].s>=a[i]) tail--;
        q[++tail].id=i,q[tail].s=a[i];
        while(q[head].id<=i-k) head++;
        mn[++o]=q[head].s;
    }

好,让我们来看这个题:

题目很简单,求连续的长度范围在p到q的最大长度和...

暴力吗?O(n2)...

我们暴力一定会用到前缀和,那我们就要来考虑能不能用前缀和保持单调性做...

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) (((a)>(b))?(a):(b))
#define min(a,b) (((a)<(b))?(a):(b))
using namespace std;
const ll N=101000;
ll ans=-1e18,sum[N],n,p,l,head,tail;
struct gg
{
    ll id,s;
}q[N];
inline ll read()
{
    ll x=0,ff=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-') ff=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*ff;
} 
int main()
{
    freopen("1.in","r",stdin);
    cin>>n>>p>>l;
    for(register int i=1;i<=n;++i) sum[i]=sum[i-1]+read();
    for(register int i=p+1;i<=n;i++) 
    {
        while(head<=tail&&sum[i-p]<=q[tail].s) --tail;
        q[++tail].id=i-p;q[tail].s=sum[i-p];
        while(head<=tail&&q[head].id<i-l) ++head;
        ans=max(ans,sum[i]-q[head].s);  
    }
    cout<<ans<<endl;
    return 0;
}

这个题我们要记住的是范围,也就是说,你每次i向前推进时,你应该把哪些点放到队列里,这里就是把i-p放进去,因为有最小长度的限制,所以

每次枚举i时,我们队列里控制的点范围其实在(i-q,i-p)之间,这样才能保证子序列时合法的子序列...

原文地址:https://www.cnblogs.com/gcfer/p/10598916.html