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;
}
posted @ 2025-10-11 16:31  Ke_scholar  阅读(13)  评论(0)    收藏  举报