E-骚区间题解:这种题首先想到要枚举区间的一个右端点,然后统计有多少合法的左端点。然后我们来求以i作为右端点,左端点在图片说明 上时,图片说明 作为区间的次大值。那么我们就从左到右枚举右端点,要使图片说明 作为次大值,先找到之前出现的离他最近的比他大的数,再找到除了这个比他大的数之外离它最近的比他大的数,就用权值线段树,线段树上第i个位置记录在枚举到当前右端点为止满足图片说明 的k即可。同理还要维护以i作为左端点,右端点在图片说明 上时, 作为区间的次小值。同理从右往左枚举左端点,也用权值线段树维护即可。
最后统计答案,我们要统计的是对于i作为右端点,在图片说明 中有多少个左端点j满足图片说明 ,这个可以用线段树来解决,也就是在图片说明 处将线段树上j的位置+1,在 处将线段树上j的位置-1,最后只要枚举右端点i,求线段树在图片说明 上的区间和即可,时间复杂度图片说明

#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;

const int N=1000005;

struct seg{
    int l,r;
    int mn,s,mx;
}t[N<<2];
int n;
ll ans;
int a[N],l1[N],r1[N],l2[N],r2[N];
vector<pair<int,int> > vec[N];

void update(int k){
    t[k].mx=max(t[k<<1].mx,t[k<<1|1].mx);
    t[k].mn=min(t[k<<1].mn,t[k<<1|1].mn);
    t[k].s=t[k<<1].s+t[k<<1|1].s;
}

void build(int k,int l,int r){
    t[k].l=l; t[k].r=r;
    t[k].mn=n+1; t[k].mx=0; t[k].s=0;
    if (l==r) return;
    int mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    update(k);
}

void modify_mx(int k,int p,int w){
    if (t[k].l==t[k].r){
        t[k].mx=w;
        return;
    }
    int mid=(t[k].l+t[k].r)>>1;
    if (p<=mid) modify_mx(k<<1,p,w);
    else modify_mx(k<<1|1,p,w);
    update(k);
}

int find_mx(int k,int L,int R){
    if (L>R) return 0;
    if (L<=t[k].l&&t[k].r<=R) return t[k].mx;
    int mid=(t[k].l+t[k].r)>>1;
    if (R<=mid) return find_mx(k<<1,L,R);
    if (L>mid) return find_mx(k<<1|1,L,R);
    return max(find_mx(k<<1,L,R),find_mx(k<<1|1,L,R));
}

int find_mn(int k,int L,int R){
    if (L>R) return n+1;
    if (L<=t[k].l&&t[k].r<=R) return t[k].mn;
    int mid=(t[k].l+t[k].r)>>1;
    if (R<=mid) return find_mn(k<<1,L,R);
    if (L>mid) return find_mn(k<<1|1,L,R);
    return min(find_mn(k<<1,L,R),find_mn(k<<1|1,L,R));
}

void modify_mn(int k,int p,int w){
    if (t[k].l==t[k].r){
        t[k].mn=w;
        return;
    }
    int mid=(t[k].l+t[k].r)>>1;
    if (p<=mid) modify_mn(k<<1,p,w);
    else modify_mn(k<<1|1,p,w);
    update(k);
}

void modify(int k,int p,int w){
    if (t[k].l==t[k].r){
        t[k].s+=w;
        return;
    }
    int mid=(t[k].l+t[k].r)>>1;
    if (p<=mid) modify(k<<1,p,w);
    else modify(k<<1|1,p,w);
    update(k);
}

int query(int k,int L,int R){
    if (L<=t[k].l&&t[k].r<=R) return t[k].s;
    int mid=(t[k].l+t[k].r)>>1;
    if (R<=mid) return query(k<<1,L,R);
    if (L>mid) return query(k<<1|1,L,R);
    return query(k<<1,L,R)+query(k<<1|1,L,R);
}

int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,1,n);
    for (int i=1;i<=n;i++){
        if (a[i]<n){
            int p=find_mx(1,a[i]+1,n);
            if (p!=0){
                r1[i]=p;
                l1[i]=find_mx(1,a[p]+1,n)+1;
                l1[i]=max(l1[i],find_mx(1,a[i]+1,a[p]-1)+1);
            }
        }
        modify_mx(1,a[i],i);
    }
    build(1,1,n);
    for (int i=n;i>=1;i--){
        if (a[i]>1){
            int p=find_mn(1,1,a[i]-1);
            if (p!=n+1){
                l2[i]=p;
                r2[i]=find_mn(1,1,a[p]-1)-1;
                r2[i]=min(r2[i],find_mn(1,a[p]+1,a[i]-1)-1);
            }
        }
        modify_mn(1,a[i],i);
    }
    for (int i=1;i<=n;i++)
        if (l2[i]&&r2[i]){
            vec[l2[i]].push_back(make_pair(i,1));
            vec[r2[i]+1].push_back(make_pair(i,-1));
        }
    for (int i=1;i<=n;i++){
        for (int j=0;j<vec[i].size();j++) modify(1,vec[i][j].first,vec[i][j].second);
        if (l1[i]&&r1[i]) ans+=1ll*query(1,l1[i],r1[i]);
    }
    printf("%lld\n",ans);
    return 0;
}