CF 548 D. Mike and Feet 单调栈(从大到小维护)

题意:给出序列a,定义f(l,r)为min(a[l],a[l+1]..a[r]) 
n<=2e5,a[i]<=1e9.问区间长度分别为1,2..n时,对应f的最大值分别为多少?


用单调栈预处理出每个a[i]作为最小值时 能延伸到的左右端点[L,R].
然后要更新ans[1...R-L+1]为max(ans[1..R-L+1],a[i]) 暴力点用线段树区间set操作,
想想都麻烦,看到ans是非递增的 然后每次更新都又是前缀

在预处理完序列a以后 将序列a用优先队列从大到小弹出来.维护当前ans最远更新到的右端点rg,每次从rg开始更新即可.

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+5,inf=0x3f3f3f3f;
int n,top=0,a[N],s[N];
int le[N],rg[N],ans[N];
priority_queue<ii> q;
void solve()
{
    int R=0;
    while(!q.empty()&&R<n)
    {
        ii u=q.top();
        q.pop();
        int val=u.first,p=u.second;
        int len=rg[p]-le[p]+1;
        while(R<len)
            ans[++R]=val;
    }
    for(int i=1;i<=n;i++)
        printf("%d ",ans[i]);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        q.push(ii(a[i],i));
        while(top&&a[s[top]]>a[i])
            rg[s[top]]=i-1,top--;

        s[++top]=i;
    }
    while(top)
        rg[s[top]]=n,top--;

    for(int i=n;i>=1;i--)
    {
        while(top&&a[s[top]]>a[i])
            le[s[top]]=i+1,top--;
        s[++top]=i;
    }
    while(top)
        le[s[top]]=1,top--;
    solve();
    return 0;
}

法2

  1. For (i, 0,n ) {
  2. int len = r [i ] - l [i ] - 1 ;
  3. smax (ans [len ], a [i ] ) ;
  4. }
  5. rof (i,n, - 1 )
  6. smax (ans [i ], ans [i + 1 ] ) ;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值