【题解】P6503 DIFERENCIJA

题面

题目传送门

前言

绿题,爆切我

世界,遗忘我

正文

这是一个经典操作:找到一个值为为最大值的最大区间长度/区间个数

那么在单调栈里这个数的前一个数就是他的左边界限,反过来做一下就能确定右端点

最小值一样

直接贴一个很清晰的题解代码

代码

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<stack>

#define int long long
const int MN=3e5+5;

using namespace std;

int a[MN];
int Lmax[MN],Rmax[MN],Lmin[MN],Rmin[MN];
stack<int>s;
int n;

signed main(void){

    cin>>n;
    for(int i=1;i<=n;i++)cin>>a[i];

    for(int i=1;i<=n;i++){
        while(!s.empty()&&a[s.top()]<=a[i])s.pop();
        if(s.empty())Lmax[i]=0;
        else Lmax[i]=s.top();
        s.push(i);
    }

    while(!s.empty())s.pop();
    for(int i=1;i<=n;i++){
        while(!s.empty()&&a[s.top()]>=a[i])s.pop();
        if(s.empty())Lmin[i]=0;
        else Lmin[i]=s.top();
        s.push(i);
    }

    while(!s.empty())s.pop();
    for(int i=n;i>=1;i--){
        while(!s.empty()&&a[s.top()]<a[i])s.pop();
        if(s.empty())Rmax[i]=n+1;
        else Rmax[i]=s.top();
        s.push(i);
    }

    while(!s.empty())s.pop();
    for(int i=n;i>=1;i--){
        while(!s.empty()&&a[s.top()]>a[i])s.pop();
        if(s.empty())Rmin[i]=n+1;
        else Rmin[i]=s.top();
        s.push(i);
    }

    int ans=0;
    for(int i=1;i<=n;i++){
        ans=ans+a[i]*(i-Lmax[i])*(Rmax[i]-i);
        ans=ans-a[i]*(i-Lmin[i])*(Rmin[i]-i);
    }

    cout<<ans<<endl;

    return 0;
}

后记

不 ~ 开 ~ 心 ~

完结撒花!

posted @ 2025-01-21 08:00  sunxuhetai  阅读(20)  评论(0)    收藏  举报