51nod 1349 最大值【单调栈】

Description

有一天,小a给了小b一些数字,让小b帮忙找到其中最大的数,由于小b是一个程序猿,当然写了一个代码很快的解决了这个问题。

这时,邪恶的小c又出现了,他问小b,假如我只需要知道这些数字中的某个区间的最大值,你还能做嘛?

小b经过七七四十九天的思考,终于完美的解决了这道题目,这次,他想也让小c尝尝苦头,于是他问小c,我现在想知道存在多少不同的区间的最大值大于等于k,你还能做吗?

这次,小c犯了难,他来请教身为程序猿的你。

Hint:一个区间指al,al+1,…,ar这一段的数且l<=r,一个区间的最大值指max{al,al+1,…,ar},两个区间不同当且仅当[l1,r1],[l2,r2]中l1不等于l2或r1不等于r2

题解

这题是一个叫做控制区间的idea。考虑枚举某一个数为某区间的最大值,那么,这个区间的边界就是前后第一个比它的数(先不考虑相等的情况)。这个显然单调栈就可以处理,那么以当前枚举的数为最大值的区间个数就是 (iL[i])(R[i]i) 。对于两个数相等的情况,只要处理一下,使得默认前面或后面的数更大就可以防止因两数相等而重复计算的问题。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 100006
#define LL long long
using namespace std;
inline char nc(){
    static char buf[100000],*i=buf,*j=buf;
    return i==j&&(j=(i=buf)+fread(buf,1,100000,stdin),i==j)?EOF:*i++;
}
inline int _read(){
    char ch=nc();int sum=0;
    while(!(ch>='0'&&ch<='9'))ch=nc();
    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();
    return sum;
}
int n,T,top,stack[maxn],L[maxn],R[maxn],a[maxn];
LL sum[maxn];
void push(int x,int p){
    while(top&&(a[stack[top]]<a[x]||a[stack[top]]==a[x]&&p))top--;
    stack[++top]=x;
}
int main(){
    freopen("maximum.in","r",stdin);
    freopen("maximum.out","w",stdout);
    n=_read();
    for(int i=1;i<=n;i++)a[i]=_read();
    for(int i=1;i<=n;i++){
        push(i,0);
        L[i]=stack[top-1]+1;
    }
    top=0;stack[0]=n+1;
    for(int i=n;i>=1;i--){
        push(i,1);
        sum[a[i]]+=(LL)(i-L[i]+1)*(stack[top-1]-i);
    }
    for(int i=100000;i>=1;i--)sum[i]+=sum[i+1];
    T=_read();
    while(T--){
        int x=_read();
        printf("%lld\n",sum[x]);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值