2023 ICPC 沈阳区域赛 K
K. Maximum Rating
数据结构。
考虑最大化变化次数,显然是先涨分再掉分,最小化相反,先掉分再涨分,从最大到最小,每次拿一个正数小的去给到负数那边,变化次数就可以减少一,最终最大到最小之间都可以取到,假设正数排序后前 \(k\) 小的和小于等于负数和,说明我们就从最大值再变化 \(k\) 次,最终答案就是 \(k+1\)。
对正数离散化后可以用线段树二分去做。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
template<class Info>
struct SegmentTree {
int n;
std::vector<Info> info;
SegmentTree() : n(0) {}
SegmentTree(int n_, Info v_ = Info()) {
init(n_, v_);
}
template<class T>
SegmentTree(std::vector<T> init_) {
init(init_);
}
void init(int n_, Info v_ = Info()) {
init(std::vector(n_, v_));
}
template<class T>
void init(std::vector<T> init_) {
n = init_.size();
info.assign(4 << std::__lg(n), Info());
std::function<void(int, int, int)> build = [&](int p, int l, int r) {
if (r - l == 1) {
info[p] = init_[l];
return;
}
int m = (l + r) / 2;
build(2 * p, l, m);
build(2 * p + 1, m, r);
pull(p);
};
build(1, 0, n);
}
void pull(int p) {
info[p] = info[2 * p] + info[2 * p + 1];
}
void modify(int p, int l, int r, int x, const Info &v) {
if (r - l == 1) {
info[p] = info[p] + v;
return;
}
int m = (l + r) / 2;
if (x < m) {
modify(2 * p, l, m, x, v);
} else {
modify(2 * p + 1, m, r, x, v);
}
pull(p);
}
void modify(int p, const Info &v) {
modify(1, 0, n, p, v);
}
int rangeQuery(int p, int l, int r, int x, int y, i64 k) {
if (l >= y || r <= x) {
return 0;
}
if (r - l == 1) {
if(k >= info[p].sum){
return info[p].cnt + 1;
}
int x = info[p].sum / info[p].cnt;
return k / x + 1;
}
int m = (l + r) / 2;
if(info[2 * p].sum >= k) {
return rangeQuery(2 * p, l, m, x, y, k);
}
return info[2 * p].cnt + rangeQuery(2 * p + 1, m, r, x, y, k - info[2 * p].sum);
}
int rangeQuery(int l, int r, i64 k) {
return rangeQuery(1, 0, n, l, r, k);
}
};
struct Info {
i64 sum = 0;
int cnt = 0;
};
Info operator+(const Info &l, const Info &r) {
return {l.sum + r.sum, l.cnt + r.cnt};
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, q;
std::cin >> n >> q;
i64 neg = 0;
std::vector<int> a(n), val;
for(int i = 0; i < n; i += 1) {
std::cin >> a[i];
if(a[i] > 0) {
val.push_back(a[i]);
} else {
neg += a[i];
}
}
std::vector<std::array<int,2>> qry(q);
for(auto &[x, v] : qry) {
std::cin >> x >> v;
if(v > 0) {
val.push_back(v);
}
}
sort(val.begin(), val.end());
SegmentTree<Info> seg(val.size() + 1);
std::vector<int> t(n);
for(int i = 0; i < n; i += 1) {
if(a[i] > 0) {
t[i] = lower_bound(val.begin(), val.end(), a[i]) - val.begin();
seg.modify(t[i], {a[i], 1});
}
}
for(auto &[x, v] : qry) {
x -= 1;
if(a[x] > 0) {
seg.modify(t[x], {-a[x], -1});
} else {
neg -= a[x];
}
a[x] = v;
if(a[x] > 0) {
t[x] = lower_bound(val.begin(), val.end(), v) - val.begin();
seg.modify(t[x], {v, 1});
} else {
neg += v;
}
int ans = seg.rangeQuery(0, val.size() + 1, -neg);
std::cout << ans << "\n";
}
return 0;
}
也可以二分 \(k\) 再去查前 \(k\) 个数的和。
点击查看代码
#include <bits/stdc++.h>
using i64 = long long;
template<class Info>
struct SegmentTree {
int n;
std::vector<Info> info;
SegmentTree() : n(0) {}
SegmentTree(int n_, Info v_ = Info()) {
init(n_, v_);
}
template<class T>
SegmentTree(std::vector<T> init_) {
init(init_);
}
void init(int n_, Info v_ = Info()) {
init(std::vector(n_, v_));
}
template<class T>
void init(std::vector<T> init_) {
n = init_.size();
info.assign(4 << std::__lg(n), Info());
std::function<void(int, int, int)> build = [&](int p, int l, int r) {
if (r - l == 1) {
info[p] = init_[l];
return;
}
int m = (l + r) / 2;
build(2 * p, l, m);
build(2 * p + 1, m, r);
pull(p);
};
build(1, 0, n);
}
void pull(int p) {
info[p] = info[2 * p] + info[2 * p + 1];
}
void modify(int p, int l, int r, int x, const Info &v) {
if (r - l == 1) {
info[p] = info[p] + v;
return;
}
int m = (l + r) / 2;
if (x < m) {
modify(2 * p, l, m, x, v);
} else {
modify(2 * p + 1, m, r, x, v);
}
pull(p);
}
void modify(int p, const Info &v) {
modify(1, 0, n, p, v);
}
i64 rangeQuery(int p, int l, int r, int x, int y, i64 k) {
if (l >= y || r <= x) {
return 0;
}
if (r - l == 1) {
if(info[p].cnt <= k){
return info[p].sum;
}
return info[p].sum / info[p].cnt * k;
}
int m = (l + r) / 2;
if(info[2 * p].cnt >= k) {
return rangeQuery(2 * p, l, m, x, y, k);
}
return info[2 * p].sum + rangeQuery(2 * p + 1, m, r, x, y, k - info[2 * p].cnt);
}
i64 rangeQuery(int l, int r, i64 k) {
return rangeQuery(1, 0, n, l, r, k);
}
};
struct Info {
i64 sum = 0;
int cnt = 0;
};
Info operator+(const Info &l, const Info &r) {
return {l.sum + r.sum, l.cnt + r.cnt};
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n, q;
std::cin >> n >> q;
i64 neg = 0, pos = 0;
std::vector<int> a(n), val;
for(int i = 0; i < n; i += 1) {
std::cin >> a[i];
if(a[i] > 0) {
val.push_back(a[i]);
pos += 1;
} else {
neg += a[i];
}
}
std::vector<std::array<int,2>> qry(q);
for(auto &[x, v] : qry) {
std::cin >> x >> v;
if(v > 0) {
val.push_back(v);
}
}
sort(val.begin(), val.end());
SegmentTree<Info> seg(val.size() + 1);
std::vector<int> t(n);
for(int i = 0; i < n; i += 1) {
if(a[i] > 0) {
t[i] = lower_bound(val.begin(), val.end(), a[i]) - val.begin();
seg.modify(t[i], {a[i], 1});
}
}
for(auto &[x, v] : qry) {
x -= 1;
if(a[x] > 0) {
seg.modify(t[x], {-a[x], -1});
pos -= 1;
} else {
neg -= a[x];
}
a[x] = v;
if(a[x] > 0) {
t[x] = lower_bound(val.begin(), val.end(), v) - val.begin();
seg.modify(t[x], {v, 1});
pos += 1;
} else {
neg += v;
}
int lo = 0, hi = pos;
while(lo < hi){
int md = (lo + hi + 1) >> 1;
if(seg.rangeQuery(0, val.size() + 1, md) <= -neg){
lo = md;
}else{
hi = md - 1;
}
}
std::cout << lo + 1 << "\n";
}
return 0;
}