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

来源:互联网 发布:找数据的网站 编辑:程序博客网 时间:2024/06/04 18:04
题意:给出序列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]);


原创粉丝点击