版权声明:_ https://blog.csdn.net/lunch__/article/details/84885718
题意
- 次询问,每次询问一个区间所有子区间的最小值之和。
这个题想到莫队还是不难,难的是怎样做到 转移,首先我们可以用 表预处理出区间最小值的位置,并且用单调栈找到每个数左右两边第一个比它小的数记为 。当我们从区间 转移到 时,增加的区间就是 ,我们找到区间最小值的位置 后,对于区间 最小值显然是 ,然后我们再计算 的贡献,对于 这个位置产生的贡献就是 ,这个东西可以写成一个类似前缀和的形式,并且最后一定会推到 这个位置上来,那么这样子就可以做到 转移了,区间长度变短的时候就减去加的贡献就好了,复杂度
Codes
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
const int M = log2(1e5) + 1;
long long ans[N], dpl[N], dpr[N], res;
int n, q, top, size, ST[N][M], lg[N];
int a[N], Sta[N], be[N], L[N], R[N];
struct Que {
int l, r, id;
bool operator < (const Que &T) const {
if (be[l] == be[T.l]) return r < T.r;
return be[l] < be[T.l];
}
}Q[N];
int _min(int x, int y) {return a[x] < a[y] ? x : y;}
int qmin(int x, int y) {
int len = lg[y - x + 1];
return _min(ST[x][len], ST[y - (1 << len) + 1][len]);
}
void insl(int l, int r) {
int pos = qmin(l, r);
res += 1ll * a[pos] * (r - pos + 1);
res += dpr[l] - dpr[pos];
}
void insr(int l, int r) {
int pos = qmin(l, r);
res += 1ll * a[pos] * (pos - l + 1);
res += dpl[r] - dpl[pos];
}
void dell(int l, int r) {
int pos = qmin(l, r);
res -= 1ll * a[pos] * (r - pos + 1);
res -= dpr[l] - dpr[pos];
}
void delr(int l, int r) {
int pos = qmin(l, r);
res -= 1ll * a[pos] * (pos - l + 1);
res -= dpl[r] - dpl[pos];
}
int main() {
#ifdef ylsakioi
freopen("3246.in", "r", stdin);
freopen("3246.out", "w", stdout);
#endif
scanf("%d%d", &n, &q), size = sqrt(n);
for (int i = 1; i <= n; ++ i)
scanf("%d", &a[i]), ST[i][0] = i;
for (int i = 1; i <= q; ++ i) {
scanf("%d%d", &Q[i].l, &Q[i].r);
Q[i].id = i, be[Q[i].l] = Q[i].l / size;
}
sort(Q + 1, Q + q + 1);
for (int i = 2; i <= n; ++ i)
lg[i] = lg[i >> 1] + 1;
for (int j = 1; j < M; ++ j)
for (int i = 1; i + (1 << j) - 1 <= n; ++ i)
ST[i][j] = _min(ST[i][j - 1], ST[i + (1 << (j - 1))][j - 1]);
for (int i = 1; i <= n; ++ i) {
while (top && a[Sta[top]] > a[i]) R[Sta[top --]] = i;
L[i] = Sta[top], Sta[++ top] = i;
}
while (top) R[Sta[top --]] = n + 1;
for (int i = 1; i <= n; ++ i)
dpl[i] = dpl[L[i]] + 1ll * (i - L[i]) * a[i];
for (int i = n; i >= 1; -- i)
dpr[i] = dpr[R[i]] + 1ll * (R[i] - i) * a[i];
int l = 1, r = 0;
for (int i = 1; i <= q; ++ i) {
while (r < Q[i].r) insr(l, ++ r);
while (r > Q[i].r) delr(l, r --);
while (l > Q[i].l) insl(-- l, r);
while (l < Q[i].l) dell(l ++ , r);
ans[Q[i].id] = res;
}
for (int i = 1; i <= q; ++ i)
printf("%lld\n", ans[i]);
return 0;
}