题目意思如下:求区间[l,r]内所有子数组的L(i,j)之和,L(i,j)如题所说。
1、转化题目,将原公式想成两点斜率
2、证明:最大的斜率只会存在于相邻两点
3、题目转化为求一列数a[l..r],求其每个字序列中最大数的的和
4、想到单调栈模型,复杂度O(n*q)
一些陷阱:
1、数据范围:最后答案要用long long
2、计算公式:我用的是ans=sigma(l[i]*r[i]*ne[i])
3、单调栈维护时注意相等的情况
4、单调栈最后里面元素要出栈
代码如下:
#include
using namespace std;
const long long maxn = 1e6+10;
int n,q,l,r;
long long a[maxn],ne[maxn],nel[maxn],ner[maxn];
int stack[maxn];
int top;
long long ans;
int main(int argc, const char * argv[]) {
cin >> n >> q;
for (int i=0; i<n; i++) {
cin >> a[i];
if (i>0) {
ne[i] = a[i]-a[i-1];
//取绝对值
if(ne[i]<0) ne[i]=-ne[i];
}
}
for (int i=0; i<q; i++) {
cin >> l>>r;
//初始化数据
ans = 0;
for (int i=l; i<r; i++) {
nel[i]=1;ner[i]=1;
}
top = -1;
//维护单调栈,记录ne[i]左右比其小的元素个数
for (int i=l; i<r; i++) {
while (top>=0&&ne[stack[top]]<ne[i]) {
if(top>0) ner[stack[top-1]]+=ner[stack[top]];
nel[i]+=nel[stack[top]];
stack[top] = -1;
top--;
}
top++;
stack[top] = i;
}
//注意最后栈里元素要出栈
while (top>0) {
ner[stack[top-1]]+=ner[stack[top]];
top--;
}
for (int i=l; i<r; i++) {
ans+=nel[i]*ner[i]*ne[i];
}
cout << ans << endl;
}
return 0;
}