莫队 ST表 单调栈
考虑添加 r + 1 r+1 r+1到 [ l , r ] [l,r] [l,r]中产生的贡献。显然多了 r − l + 2 r-l+2 r−l+2个区间。设 [ l , r + 1 ] [l,r+1] [l,r+1]的最小值取在 p p p点,那么 p p p产生的贡献为 w [ p ] ∗ ( p − l + 1 ) w[p]*(p-l+1) w[p]∗(p−l+1),剩下的贡献可以前缀和搞一搞。 p p p可以ST表预处理后直接得到。对每个位置预处理以它为最小值的区间 [ L , R ] [L,R] [L,R],记两个前缀和 s l [ i ] sl[i] sl[i]和 s r [ i ] sr[i] sr[i]分别表示 [ 1 , i ] [1,i] [1,i]的前缀和贡献和 [ i , n ] [i,n] [i,n]的后缀和贡献。那么有 s l [ i ] = s l [ L i − 1 ] + w [ i ] ∗ ( i − L i + 1 ) sl[i]=sl[L_i-1]+w[i]*(i-L_i+1) sl[i]=sl[Li−1]+w[i]∗(i−Li+1),另一个同样。这样就可以用莫队维护了。
代码:
#include<cctype>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
#define F inline
using namespace std;
typedef long long LL;
struct query{ int l,r,id,bl,br; }q[N];
int n,m,k,tp,p,lg[N],L[N],R[N],stk[N],ST[N][18];
LL s,a[N],sl[N],sr[N],ans[N];
F char readc(){
static char buf[100000],*l=buf,*r=buf;
if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
return l==r?EOF:*l++;
}
F int _read(){
int x=0,f=1; char ch=readc();
while (!isdigit(ch)) ch=='-'?f=-1:1,ch=readc();
while (isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=readc();
return x*f;
}
F bool cmp(query a,query b){ return a.bl==b.bl?(a.br<b.br)^(a.bl&1):a.bl<b.bl; }
#define Min(x,y) (a[x]<a[y]?x:y)
F void Make(){
for (int j=1,k=log2(n);j<=k;j++)
for (int i=1;i<=n-(1<<j)+1;i++)
ST[i][j]=Min(ST[i][j-1],ST[i+(1<<j-1)][j-1]);
}
#define srch(l,r) Min(ST[l][lg[r-l+1]],ST[r-(1<<lg[r-l+1])+1][lg[r-l+1]])
#define nsrtl(l,r,f) p=srch(l,r),s+=1ll*f*(a[p]*(r-p+1)+sr[l]-sr[p])
#define nsrtr(l,r,f) p=srch(l,r),s+=1ll*f*(a[p]*(p-l+1)+sl[r]-sl[p])
int main(){
n=_read(),m=_read(),k=sqrt(n);
for (int i=1;i<=n;i++) ST[i][0]=i,a[i]=_read(),lg[i]=log2(i);
Make(),L[1]=1,stk[++tp]=1,R[n]=n;
for (int i=2;i<=n;i++){
while (tp&&a[stk[tp]]>a[i]) R[stk[tp--]]=i-1;
L[i]=stk[tp]+1,stk[++tp]=i;
}
for (int i=1;i<=tp;i++) R[stk[i]]=n;
for (int i=1;i<=n;i++) sl[i]=sl[L[i]-1]+a[i]*(i-L[i]+1);
for (int i=n;i;i--) sr[i]=sr[R[i]+1]+a[i]*(R[i]-i+1);
for (int i=1,l,r;i<=m;i++)
l=_read(),r=_read(),q[i]=(query){l,r,i,(l-1)/k+1,(r-1)/k+1};
sort(q+1,q+m+1,cmp); int l=1,r=0;
for (int i=1;i<=m;i++){
while (r<q[i].r) r++,nsrtr(l,r,1);
while (l>q[i].l) l--,nsrtl(l,r,1);
while (r>q[i].r) nsrtr(l,r,-1),r--;
while (l<q[i].l) nsrtl(l,r,-1),l++;
ans[q[i].id]=s;
}
for (int i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}