Codeforces 1862G 题解
题解
因为有这个操作:将序列 \(a\) 加上 \(\{n, n - 1, \cdots, 1\}\),考虑差分。
那么显然每次操作会将差分数组中的每个元素减去 \(1\),如果差分数组中有 \(0\),就会把 \(0\) 删除。
所以可以发现差分数组中剩下的一定是操作前的最大值。
由于操作后最大值还是最大值,最小值仍然是最小值,所以答案是 原序列最大值+差分数组最大值。
考虑用 multiset 维护原序列和差分,当有一次修改操作(将 \(x \to y\)),我们更新 multiset:
- 求出 \(x\) 在原序列中的前驱与后继。
- 在维护差分数组的
multiset中删除 \(x\) 与前驱的差和 \(x\) 与后继的差。 - 在原序列的
multiset中插入 \(y\)。 - 加入 \(y\) 与它前驱的差与 \(y\) 与它后继的差。
然后就没了。
代码
#include <bits/stdc++.h>
using namespace std;
void solve() {
int n; cin >> n;
vector <int> a(n + 1), b(n + 1);
multiset <int> s1, s2;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
b[i] = a[i];
}
sort(b.begin() + 1, b.end());
for (int i = 1; i <= n; ++i) {
s1.insert(b[i]);
if (i > 1) s2.insert(b[i] - b[i - 1]);
}
int q; cin >> q; while (q--) {
int x, y; cin >> x >> y;
s1.erase(s1.find(a[x]));
auto k = s1.upper_bound(a[x]);
if (k != s1.begin()) {
k = prev(k);
s2.erase(s2.find(a[x] - *k));
}
k = s1.upper_bound(a[x]);
if (k != s1.end()) s2.erase(s2.find(*k - a[x]));
auto l1 = s1.upper_bound(a[x]), l2 = s1.upper_bound(a[x]);
if (l1 != s1.begin() && l2 != s1.end()) {
--l1;
s2.insert(*l2 - *l1);
}
a[x] = y;
k = s1.upper_bound(y);
if (k != s1.end())
s2.insert(*k - y);
k = s1.upper_bound(y);
if (k != s1.begin()) {
k = prev(k);
s2.insert(y - *k);
}
l1 = s1.upper_bound(y), l2 = s1.upper_bound(y);
if (l1 != s1.begin() && l2 != s1.end()) {
--l1;
s2.erase(s2.find(*l2 - *l1));
}
s1.insert(y);
if (!s2.size()) cout << (*--s1.end()) << ' ';
else cout << (*--s1.end()) + (*--s2.end()) << ' ';
} cout << '\n';
}
signed main(void) {
ios :: sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
int T; cin >> T; while (T--) solve();
}

浙公网安备 33010602011771号