为啥会有一个莫队的标签啊
求出每个点左/右边第一个比它小的点的位置。(单调栈维护)
然后连边会分别构成两个森林。
在森林中统计链上信息即可求出右端点为
R
R
R左端点
>
=
L
>=L
>=L的答案之和,具体就是链上祖先和然后再求区间最小值之后差分。
再来一个前缀和就可以得到
[
L
,
R
]
[L,R]
[L,R]的区间答案。
A C C o d e \rm AC\ Code AC Code
#include<bits/stdc++.h>
#define maxn 100005
#define lim 17
#define S 300
#define LL long long
#define inf 0x3f3f3f3f
using namespace std;
int n,q,a[maxn],sta[maxn],prel[maxn],prer[maxn],lg[maxn];
LL ans[maxn],fl[maxn],fr[maxn],gl[maxn],gr[maxn];
int st[lim][maxn];
int qry(int L,int R){ int t=lg[R-L+1];return a[st[t][L]] < a[st[t][R-(1<<t)+1]] ? st[t][L] : st[t][R-(1<<t)+1]; }
int main(){
// freopen("1.in","r",stdin);
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),st[0][i] = i,(i>1?lg[i]=lg[i>>1]+1:0);
for(int j=1;j<lim;j++) for(int i=1;i+(1<<j)-1<=n;i++) st[j][i] = a[st[j-1][i]] < a[st[j-1][i+(1<<j-1)]] ? st[j-1][i] : st[j-1][i+(1<<j-1)];
a[0] = a[n+1] = -inf;
sta[sta[0] = 1] = 0;
for(int i=1;i<=n;i++){
for(;sta[0] && a[sta[sta[0]]]>=a[i];sta[0]--);
prel[i] = sta[sta[0]],fl[i] = fl[prel[i]] + 1ll * a[i] * (i - prel[i]);
gl[i] = gl[i-1] + fl[i];
sta[++sta[0]] = i;
}
sta[sta[0] = 1] = n+1;
for(int i=n;i>=1;i--){
for(;sta[0] && a[sta[sta[0]]]>=a[i];sta[0]--);
prer[i] = sta[sta[0]],fr[i] = fr[prer[i]] + 1ll * a[i] * (prer[i] - i);
gr[i] = gr[i+1] + fr[i];
sta[++sta[0]] = i;
}
for(int i=1,L,R;i<=q;i++){ scanf("%d%d",&L,&R);int p = qry(L,R);
printf("%lld\n",gr[L]+gl[R]-gl[p]-gr[p]-((R-p)*fl[p]+(p-L)*fr[p])+(p-L+1ll)*(R-p+1ll)*a[p]);
}
}