专栏文章
题解:P13963 [ICPC 2023 Nanjing R] 接雨水
P13963题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @min2p5vj
- 此快照首次捕获于
- 2025/12/01 19:35 3 个月前
- 此快照最后确认于
- 2025/12/01 19:35 3 个月前
P13963 接雨水
饭菜烧得好,媳妇回家早。
—— fjd
题目描述
给定长度为 的整数序列 ,第 次修改会将 的值增加 。在每次修改之后,计算:
其中 ,。
题目分析
如果每次修改都更新并统计答案显然无法通过本题,那么我们考虑...
对和式进行拆分:
有和式你不拆?
对和式进行拆分:
重点之一(敲黑板)
- 前缀最大值 单调不降
- 后缀最大值 单调不增
证明:
- 对于 :若 ,则 应更新为 ,因此
- 对于 :同理可证
选择数据结构维护
观察到 和 都具有区间性质,可以使用 ODT(Old Driver Tree,老司机树)来维护。
此外, 实际上就是 ,因为对于每个位置 , 都等于全局最大值一个前缀最大一个后缀最大显然合起来就是全局最大嘛。
时间复杂度
使用 ODT 维护,每次修改的均摊复杂度为 ,总复杂度 足以通过本题。
关于ODT
代码实现
CPP#include <bits/stdc++.h>
using namespace std;
#define int long long
#define IT set<node>::iterator
const int N = 1e5 + 10, INF = 1e18;
inline int read() {
int x = 0, f = 0;
char c = getchar();
while (!isdigit(c)) {
f |= c == '-';
c = getchar();
}
while (isdigit(c)) {
x = x * 10 + (c ^ 48);
c = getchar();
}
return f ? -x : x;
}
struct node {
int l, r;
mutable int v;
bool operator < (const node &x) const {
return l < x.l;
}
};
set<node> sf, sg;
int n, q, t, a[N], sum;
IT splf(int pos) {
IT it = sf.lower_bound({pos, 0, 0});
if (it != sf.end() && it->l == pos) return it;
it--;
int l = it->l, r = it->r;
int v = it->v;
sf.erase(it);
sf.insert({l, pos - 1, v});
return sf.insert({pos, r, v}).first;
}
IT splg(int pos) {
IT it = sg.lower_bound({pos, 0, 0});
if (it != sg.end() && it->l == pos) return it;
it--;
int l = it->l, r = it->r;
int v = it->v;
sg.erase(it);
sg.insert({l, pos - 1, v});
return sg.insert({pos, r, v}).first;
}
IT gtf(int pos) {
IT it = sf.lower_bound({pos, 0, 0});
if (it != sf.end() && it->l == pos) return it;
it--;
return it;
}
IT gtg(int pos) {
IT it = sg.lower_bound({pos, 0, 0});
if (it != sg.end() && it->l == pos) return it;
it--;
return it;
}
void chgf(int x) {
IT itr = gtf(x);
if (itr->v >= a[x]) return;
itr = splf(x);
IT itl = itr;
for (; itr->v < a[x] && itr != sf.end(); itr++) {
sum += (itr->r - itr->l + 1) * (a[x] - itr->v);
}
itr--;
int r = itr->r;
itr++;
sf.erase(itl, itr);
sf.insert({x, r, a[x]});
return;
}
void chgg(int x) {
IT itr = gtg(x);
if (itr->v >= a[x]) return;
itr = splg(x + 1);
IT itl = itr;
itr--;
for (; itr->v < a[x]; itr--) {
sum += (itr->r - itr->l + 1) * (a[x] - itr->v);
}
if (itr->v >= a[x]) itr++;
else {
sum += (itr->r - itr->l + 1) * (a[x] - itr->v);
}
int l = itr->l;
sg.erase(itr, itl);
sg.insert({l, x, a[x]});
return;
}
void slv() {
sum = 0;
n = read();
int mx = 0, l = 1;
for (int i = 1; i <= n; i++) {
a[i] = read();
sum -= a[i];
if (!mx) mx = a[i];
if (mx < a[i]) {
sf.insert({l, i - 1, mx});
l = i;
mx = a[i];
}
}
sf.insert({l, n, max(mx, a[n])});
mx = a[n];
l = n;
for (int i = n; i >= 1; i--) {
if (mx < a[i]) {
sg.insert({i + 1, l, mx});
l = i;
mx = a[i];
}
}
mx = max(a[1], mx);
sum -= mx * n;
sg.insert({1, l, mx});
sf.insert({n + 1, n + 100, INF});
sg.insert({-1, -100, INF});
for (IT it = sf.begin(); it->v != INF; it++) {
sum += (it->r - it->l + 1) * it->v;
}
for (IT it = sg.begin(); it != sg.end(); it++) {
if (it->v == INF) continue;
sum += (it->r - it->l + 1) * it->v;
}
int q = read();
while (q--) {
int x = read(), c = read();
a[x] += c;
if (mx < a[x]) {
sum -= (a[x] - mx) * n;
mx = a[x];
}
sum -= c;
chgf(x);
chgg(x);
cout << sum << endl;
}
sf.clear();
sg.clear();
}
signed main() {
int t = read();
while (t--) {
slv();
}
return 0;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...