题解:CF1988E Range Minimum Sum
跟 CF1913F 很像,但是简单的多。
- 给定长度为
n 的序列a 。求出对于每个i = (1, 2, \dots, n) ,序列b = [a_1, a_2, \dots, a_{i - 1}, a_{i + 1} ,a_{i +2}, \dots, n] 的价值。- 序列
c 的价值为\sum_{l=1}^{|c|} \sum_{r=l}^{|c|} \min _{l \le i \le r} c_i 。
若没有删除操作,而是直接求原序列
只要
仍然考虑这种拆贡献的做法。我们令
分类讨论:
除了
// Problem: Range Minimum Sum
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1988E
// Memory Limit: 500 MB
// Time Limit: 4000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
typedef long long ll;
#define int ll
int T, n, a[N];
int st[N][20];
int L[N], R[N];
int f[N];
int f_sum[N]; // f 的差分数组,用于区间加
void add(int l, int r, int d) {
if (l <= r) f_sum[l] += d, f_sum[r + 1] -= d;
}
void solve() {
cin >> n;
for (int i = 1; i <= n; ++ i ) {
cin >> a[i];
st[i][0] = a[i];
f[i] = f_sum[i] = 0;
}
for (int j = 1; j < 20; ++ 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]);
auto RMQ = [&](int l, int r) {
int k = log2(r - l + 1);
return min(st[l][k], st[r - (1 << k) + 1][k]);
};
stack<int> stk;
for (int i = 1; i <= n; ++ i ) {
while (stk.size() && a[stk.top()] > a[i]) stk.pop();
L[i] = stk.size() ? stk.top() : 0;
stk.push(i);
}
while (stk.size()) stk.pop();
for (int i = n; i; -- i ) {
while (stk.size() && a[stk.top()] > a[i]) stk.pop();
R[i] = stk.size() ? stk.top() : n + 1;
stk.push(i);
}
for (int j = 1; j <= n; ++ j ) {
// 删除 a[j] 后,哪些 f(i) 会收到影响?
add(1, L[j] - 1, a[j] * (j - L[j]) * (R[j] - j));
add(R[j] + 1, n, a[j] * (j - L[j]) * (R[j] - j));
add(L[j] + 1, j - 1, a[j] * (j - 1 - L[j]) * (R[j] - j));
add(j + 1, R[j] - 1, a[j] * (j - L[j]) * (R[j] - 1 - j));
}
for (int i = 1; i <= n; ++ i ) f[i] = (f_sum[i] += f_sum[i - 1]);
for (int i = 1; i <= n; ++ i ) {
// 将 L[i] 删除
int l = 1, r = L[i] - 1, res = 0;
while (l <= r) {
int mid = l + r >> 1;
if (RMQ(mid, L[i] - 1) > a[i]) res = L[i] - mid, r = mid - 1;
else l = mid + 1;
}
res += i - L[i];
f[L[i]] += a[i] * res * (R[i] - i);
}
for (int i = 1; i <= n; ++ i ) {
// 将 R[i] 删除
int l = R[i] + 1, r = n, res = 0;
while (l <= r) {
int mid = l + r >> 1;
if (RMQ(R[i] + 1, mid) > a[i]) res = mid - R[i], l = mid + 1;
else r = mid - 1;
}
res += R[i] - i;
f[R[i]] += a[i] * (i - L[i]) * res;
}
for (int i = 1; i <= n; ++ i ) cout << f[i] << ' ';
cout << '\n';
return;
}
signed main() {
cin >> T;
while (T -- ) solve();
return 0;
}