1 条题解
-
0
长的后缀使得区间最小值均 。
具体做法:在 上二分,用 RMQ(ST 表)查询区间最小值,找到最远的左端点 使得 。新的“左延伸长度”为 。
贡献为 ,加到 上。
的处理
同理,在 上二分找到最远的右端点 使得 。新的“右延伸长度”为 。
贡献为 ,加到 上。
RMQ 预处理
使用 ST 表,
st[i][j]表示从 开始长度 的区间最小值。查询 的最小值:令 ,则:
复杂度
- 单调栈求 :
- ST 表预处理:
- 差分区间的加:
- 处理 和 时二分 + RMQ:每次 ,总计
总复杂度 ,可以满足 , 的限制。
参考代码
#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]; 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) { 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) { 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) { 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'; } signed main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> T; while (T--) solve(); return 0; }
- 1
信息
- ID
- 6825
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者