预处理每个a[i]数作为最左的最小值向左右延伸到的位置L[i],R[i],则l=L[i]..i,r=i..R[i]的区间的最小值为a[i],且最后每个区间不重不漏
令与y轴平行的扫描线沿x轴负方向扫描,维护扫描线上每个y坐标上的答案关于x坐标的一次函数的系数,可以发现每个矩形加操作可以拆成四次区间加(进入/离开扫描线时对区间内的一次函数的两个系数的影响均为一个常数),而询问则为区间求和(区间内一次函数加起来再代入当前x求一次值),至此可以树状数组/线段树维护
#include<cstdio>
#include<algorithm>
typedef long long i64;
const int N=100007;
int n,q,a[N],ss[N],sp=0,ls[N],rs[N];
i64 ans[N];
char buf[N*50],*ptr=buf-1;
int _(){
int x=0,f=1,c=*++ptr;
while(c<48)c==‘-‘&&(f=-1),c=*++ptr;
while(c>47)x=x*10+c-48,c=*++ptr;
return x*f;
}
i64 ks[2][N],bs[2][N];
void add(i64*f1,i64*f2,int w0,i64 x){
if(!w0)return;
for(int w=w0;w;w-=w&-w)f1[w]+=x;
x*=w0;
for(int w=w0;w<=n;w+=w&-w)f2[w]+=x;
}
i64 sum(i64*f1,i64*f2,int w0){
if(!w0)return 0;
i64 s=0;
for(int w=w0;w<=n;w+=w&-w)s+=f1[w];
s*=w0;
for(int w=w0-1;w;w-=w&-w)s+=f2[w];
return s;
}
struct Q{
int l,r,id;
void run(){
ans[id]=sum(ks[0],ks[1],r)*l+sum(bs[0],bs[1],r);
}
}qs[N];
bool operator<(Q a,Q b){return a.l>b.l;}
struct ev{
int l,r1,r2;
i64 k,b;
void run(){
add(ks[0],ks[1],r2,k);
add(ks[0],ks[1],r1-1,-k);
add(bs[0],bs[1],r2,b);
add(bs[0],bs[1],r1-1,-b);
}
}e[N*2];
bool operator<(const ev&a,const ev&b){return a.l>b.l;}
int ep=0;
int main(){
fread(buf,1,sizeof(buf),stdin);
n=_();q=_();
for(int i=1;i<=n;++i)a[i]=_();
for(int i=1;i<=n;++i){
while(sp&&a[ss[sp]]>a[i])rs[ss[sp--]]=i-1;
ss[++sp]=i;
}
while(sp)rs[ss[sp--]]=n;
for(int i=n;i;--i){
while(sp&&a[ss[sp]]>=a[i])ls[ss[sp--]]=i+1;
ss[++sp]=i;
}
while(sp)ls[ss[sp--]]=1;
for(int i=1;i<=n;++i){
e[ep++]=(ev){i+1,i,rs[i],-a[i],i64(i+1)*a[i]};
e[ep++]=(ev){ls[i],i,rs[i],a[i],i64(-ls[i])*a[i]};
}
std::sort(e,e+ep);
for(int i=0;i<q;++i){
qs[i].l=_();
qs[i].r=_();
qs[i].id=i;
}
std::sort(qs,qs+q);
for(int i=0,p=0;i<q;++i){
while(p<ep&&e[p].l>=qs[i].l)e[p++].run();
qs[i].run();
}
for(int i=0;i<q;++i)printf("%lld\n",ans[i]);
return 0;
}