传送门
题解:
由于保证给出的是一个排列,我们考虑在这上面做一点文章。
显然这种情况下连续段 [ l , r ] [l,r] [l,r]一定有 m a x [ l : r ] − m i n [ l : r ] = r − l max[l:r]-min[l:r]=r-l max[l:r]−min[l:r]=r−l
考虑离线,将所有询问按照右端点排序,每一个合法的区间在左端点+1。
维护区间 m a x [ l : r ] − m i n [ l : r ] − ( r − l ) max[l:r]-min[l:r]-(r-l) max[l:r]−min[l:r]−(r−l)的最小值和最小值出现次数(显然这个东西是恒非负的),则我们我们一边平移右端点一边用单调栈维护区间 m a x max max和 m i n min min的变化,显然 [ r : r ] [r:r] [r:r]这个区间的值是 0 0 0,那么全局最小值就是 0 0 0,当前全局最小值出现次数就是右端点为 r r r的合法区间个数。为了计算所有合法区间我们维护一下历史最小值出现次数之和就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
using pii=std::pair<int,int>;
#define fi first
#define se second
cs int N=1.2e5+7;
ll sum[N<<2];
int cnt[N<<2],mn[N<<2],tim[N<<2],tag[N<<2];
#define lc u<<1
#define rc lc|1
inline void build(int u,int l,int r){
mn[u]=l,cnt[u]=1;if(l==r)return ;
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
}
inline void add_v(int u,int ad){mn[u]+=ad,tag[u]+=ad;}
inline void add_t(int u,int ad){tim[u]+=ad,sum[u]+=(ll)ad*cnt[u];}
inline void pushdown(int u){
if(tag[u]){
add_v(lc,tag[u]);
add_v(rc,tag[u]);
tag[u]=0;
}
if(tim[u]){
if(mn[lc]==mn[u])add_t(lc,tim[u]);
if(mn[rc]==mn[u])add_t(rc,tim[u]);
tim[u]=0;
}
}
inline void pushup(int u){
mn[u]=std::min(mn[lc],mn[rc]);
sum[u]=sum[lc]+sum[rc];
cnt[u]=(mn[lc]==mn[u]?cnt[lc]:0)+(mn[rc]==mn[u]?cnt[rc]:0);
}
inline void modify(int u,int l,int r,int ql,int qr,int val){
if(ql<=l&&r<=qr)return add_v(u,val);
pushdown(u);int mid=l+r>>1;
if(ql<=mid)modify(lc,l,mid,ql,qr,val);
if(mid<qr)modify(rc,mid+1,r,ql,qr,val);
pushup(u);
}
inline ll query(int u,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr)return sum[u];
pushdown(u);int mid=l+r>>1;
if(qr<=mid)return query(lc,l,mid,ql,qr);
if(mid<ql)return query(rc,mid+1,r,ql,qr);
return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
}
#undef lc
#undef rc
ll ans[N];int n,m;
int a[N],tp_mx,stk_mx[N],tp_mn,stk_mn[N];
std::vector<pii> vec[N];
signed main(){
#ifdef zxyoi
freopen("good_segment.in","r",stdin);
#endif
n=gi();build(1,1,n);
for(int re i=1;i<=n;++i)a[i]=gi();
m=gi();for(int re i=1;i<=m;++i){
int l=gi(),r=gi();
vec[r].push_back(pii(l,i));
}
for(int re i=1;i<=n;++i){
add_v(1,-1);
while(tp_mx&&a[stk_mx[tp_mx]]<a[i])
modify(1,1,n,stk_mx[tp_mx-1]+1,stk_mx[tp_mx],a[i]-a[stk_mx[tp_mx]]),--tp_mx;
while(tp_mn&&a[stk_mn[tp_mn]]>a[i])
modify(1,1,n,stk_mn[tp_mn-1]+1,stk_mn[tp_mn],a[stk_mn[tp_mn]]-a[i]),--tp_mn;
stk_mx[++tp_mx]=stk_mn[++tp_mn]=i;add_t(1,1);
for(pii t:vec[i])ans[t.se]=query(1,1,n,t.fi,i);
}
for(int re i=1;i<=m;++i)cout<<ans[i]<<"\n";
return 0;
}