# Problem

## Description

$$5, 2, 4, 1, 3$$，询问给定的两个数为 $$1$$$$3$$，那么 $$a[1 \colon 3]$$$$6$$ 个子序列 $$a[1 \colon 1], a[2 \colon 2], a[3 \colon 3], a[1 \colon 2],a[2 \colon 3], a[1 \colon 3]$$，这 $$6$$ 个子序列的最小值之和为 $$5+2+4+2+2+2=17$$

## Sample

### Input

5 5
5 2 4 1 3
1 5
1 3
2 4
3 5
2 5


### Output

28
17
11
11
17


# Mentality

$f_l[r+1]=(r+1-ll[r+1])*a[r]+(ll[r+1]-ll[ll[r+1]])*a[ll[r+1]]+\dots + 0$

$f_l[r+1]=(r+1-ll[r+1])*a[r]+f_l[ll[r+1]]$

$a[p]*(p-l+1)+f_l[r+1]-f_l[p]$

# Code

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
using namespace std;
int n, size, Q, a[100001];
int minn[100001][18], pos[100001][18], Log[100001];
int top, ll[100001], rr[100001], stack[100001];
int L, R;
long long ans, Ans[100001], fr[100001], fl[100001];
struct node {
int l, r, d;
} k[100001];
bool cmp(node a, node b) {
return (a.l / size) == (b.l / size) ? a.r < b.r : (a.l / size) < (b.l / size);
}
int find(int l, int r) {
if (l > r) return 0;
if (l == r) return pos[l][0];
int x = Log[r - l], p;
return minn[l][x] > minn[r - (1 << x) + 1][x] ? pos[r - (1 << x) + 1][x]
: pos[l][x];

}  //寻找最小值位置
void init() {
cin >> n >> Q;
size = sqrt(n);
int now = 2;
for (int i = 2; i <= (int)1e5; i++) {
Log[i] = Log[i - 1];
if (i == now) Log[i]++, now <<= 1;
}  //预处理对数
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
minn[i][0] = a[i], pos[i][0] = i;
}
for (int i = 1; i <= Q; i++) scanf("%d%d", &k[i].l, &k[i].r), k[i].d = i;
sort(k + 1, k + Q + 1, cmp);  //离线询问
for (int j = 1; j <= 17; j++)
for (int i = 1; i <= n - (1 << j) + 1; i++) {
pos[i][j] = pos[i][j - 1],
minn[i][j] = min(minn[i][j - 1], minn[i + (1 << (j - 1))][j - 1]);
if (minn[i][j] != minn[i][j - 1])
pos[i][j] = pos[i + (1 << (j - 1))][j - 1];
}  //预处理 rmq
stack[top = 0] = 0;
for (int i = 1; i <= n; i++) {
while (top && a[stack[top]] >= a[i]) top--;
ll[i] = stack[top], stack[++top] = i;
}
for (int i = 1; i <= n; i++) fl[i] = fl[ll[i]] + 1ll * (i - ll[i]) * a[i];
stack[top = 0] = n + 1;
for (int i = n; i >= 1; i--) {
while (top && a[stack[top]] >= a[i]) top--;
rr[i] = stack[top], stack[++top] = i;
}  //单调栈处理 ll，rr 数组
for (int i = n; i >= 1; i--)
fr[i] = fr[rr[i]] + 1ll * (rr[i] - i) * a[i];  //计算 fl，fr 数组
}
long long workr(int x) {
int p = find(L, x);
return 1ll * a[p] * (p - L + 1) + fl[x] - fl[p];
}
long long workl(int x) {
int p = find(x, R);
return 1ll * a[p] * (R - p + 1) + fr[x] - fr[p];
}
void solve() {
L = k[1].l, R = k[1].l - 1;
for (int i = 1; i <= Q; i++) {
while (R < k[i].r) ans += workr(++R);
while (L > k[i].l) ans += workl(--L);
while (R > k[i].r) ans -= workr(R--);
while (L < k[i].l) ans -= workl(L++);
Ans[k[i].d] = ans;
}
}
int main() {
init();  //预处理和读入
solve();
for (int i = 1; i <= Q; i++) printf("%lld\n", Ans[i]);
}


posted @ 2019-03-31 17:23  洛水·锦依卫  阅读(265)  评论(0编辑  收藏  举报