题目链接:BZOJ4540
题目大意
给定一个序列,有若干个询问,问某个连续子序列的所有连续子序列的最小值的和,即
∑l≤i≤j≤rmin[i..j]
分析
1. 首先一看这道题,长得就非常的“莫队”,那么我们该怎么转移呢?
2. 若我们已经得到了区间
[l..r−1]
的答案,那么对于新加入的元素
r
,我们只考虑包含
3. 设
pre[i]
为
i
左边第一个比
4. 那么
sum[r]
与
S
有什么关系呢?
5. 设
6. 那么对于其他三种情况,对称的做一下就好了。
上代码
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int M = 20;
const int SQR = 320;
const int N = 1e5 + 10;
int n, m;
inline int read() {
char ch;
int ans = 0, neg = 1;
while (ch = getchar(), ch < '0' || ch > '9')
if (ch == '-') neg = -1;
while (ch >= '0' && ch <= '9')
ans = ans * 10 + ch - '0', ch = getchar();
return ans * neg;
}
struct nodeQry {
int l, r, bl, id;
inline void input(int a) {
l = read(), r = read(), bl = l / SQR, id = a;
}
inline bool operator < (const nodeQry &a) const {
return bl != a.bl ? bl < a.bl : r < a.r;
}
} qry[N];
// nxt和suml就是pre和sumr的对称情况
int val[N], pre[N], nxt[N];
int minp[N][M];
LL suml[N], sumr[N];
#define p1 minp[i][j - 1]
#define p2 minp[k][j - 1]
void calcST() { //ST表
for (int i = 1; i <= n; i++) minp[i][0] = i;
for (int j = 1; (1 << j) <= n; j++)
for (int i = 1; i <= n; i++) {
int k = i + (1 << (j - 1));
if (k > n) minp[i][j] = minp[i][j - 1];
else minp[i][j] = (val[p1] <= val[p2] ? p1 : p2);
}
}
#undef p1
#undef p2
void calcPN() {
stack <int> S;
for (int i = 1; i <= n; i++) {
while (!S.empty() && val[S.top()] > val[i])
nxt[S.top()] = i, S.pop();
S.push(i);
}
while (!S.empty()) nxt[S.top()] = n + 1, S.pop();
for (int i = n; i >= 1; i--) {
while (!S.empty() && val[S.top()] > val[i])
pre[S.top()] = i, S.pop();
S.push(i);
}
while (!S.empty()) pre[S.top()] = 0, S.pop();
}
void calcSum() {
for (int i = 1; i <= n; i++)
sumr[i] = sumr[pre[i]] + (LL)val[i] * (i - pre[i]);
for (int i = n; i >= 1; i--)
suml[i] = suml[nxt[i]] + (LL)val[i] * (nxt[i] - i);
}
void init() {
n = read(), m = read();
for (int i = 1; i <= n; i++) val[i] = read();
for (int i = 1; i <= m; i++) qry[i].input(i);
calcST(), calcPN(), calcSum();
sort(qry + 1, qry + m + 1);
}
struct nodeAns {
int id; LL cnt;
nodeAns() {}
nodeAns(int a, LL b) : id(a), cnt(b) {}
inline bool operator < (const nodeAns &a) const {
return id < a.id;
}
} ans[N];
LL tot;
#define p1 minp[l][k]
#define p2 minp[r - (1 << k) + 1][k]
int len[N];
void calcK() {
int k = 0;
for (int i = 1; i <= n; i++) {
while (1 << (k + 1) <= i) k++;
len[i] = k;
}
}
inline int getMin(int l, int r) {
int k = len[r - l + 1];
return (val[p1] <= val[p2] ? p1 : p2);
}
void figure() {
calcK();
int l = qry[1].l, r = l, p = minp[l][0];
tot = (LL)val[p];
for (int i = 1; i <= m; i++) {
while (r < qry[i].r) {
p = getMin(l, ++r);
tot += sumr[r] - sumr[p] + (LL)val[p] * (p - l + 1);
}
while (l > qry[i].l) {
p = getMin(--l, r);
tot += suml[l] - suml[p] + (LL)val[p] * (r - p + 1);
}
while (r > qry[i].r) {
tot -= sumr[r] - sumr[p] + (LL)val[p] * (p - l + 1);
p = getMin(l, --r);
}
while (l < qry[i].l) {
tot -= suml[l] - suml[p] + (LL)val[p] * (r - p + 1);
p = getMin(++l, r);
}
ans[i] = nodeAns(qry[i].id, tot);
}
sort(ans + 1, ans + m + 1);
for (int i = 1; i <= m; i++)
printf("%lld\n", ans[i].cnt);
}
int main() {
init();
figure();
return 0;
}
以上