题意:
求一个序列的所有子序列的L(h)的和
分析:
我们可以把序列中所有的元素两两连边,我们发现相邻的两个元素一定是最大斜率贡献者之一,也就是L(h)
然后我们用单调栈维护相邻元素差值作为最大值,左右能维护到的距离Li,Ri
注意这里如果区间范围最左最左的值相等的话,会把最大的这个序列算2次
所以这里我们Li维护的是>=,Ri维护是>就没有问题了
不然sample 1就跪了,出题人好良心
然后累加贡献,ans=∑r−1i=ldifi∗(i−Li)∗(Ri−i)
代码:
//
// Created by TaoSama on 2015-11-25
// Copyright (c) 2015 TaoSama. All rights reserved.
//
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>
using namespace std;
#define pr(x) cout << #x << " = " << x << " "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;
int n, q;
int a[N], b[N], L[N], R[N];
int stk[N], top;
int main() {
#ifdef LOCAL
freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
ios_base::sync_with_stdio(0);
while(scanf("%d%d", &n, &q) == 2) {
for(int i = 1; i <= n; ++i) scanf("%d", a + i);
while(q--) {
int l, r; scanf("%d%d", &l, &r);
int k = r - l;
for(int i = 1; i <= k; ++i) b[i] = abs(a[l + i] - a[l + i - 1]);
top = 0;
for(int i = 1; i <= k; ++i) {
while(top && b[stk[top]] <= b[i]) --top;
L[i] = top ? stk[top] : 0;
stk[++top] = i;
}
top = 0;
for(int i = k; i; --i) {
while(top && b[stk[top]] < b[i]) --top;
R[i] = top ? stk[top] : k + 1;
stk[++top] = i;
}
long long ans = 0;
for(int i = 1; i <= k; ++i)
ans += 1LL * b[i] * (i - L[i]) * (R[i] - i);
printf("%I64d\n", ans);
}
}
return 0;
}