牛客网暑期ACM多校训练营(第七场) F、Energy stones 区间修改+树状数组维护单点状态

Energy stones


题意

  • 每颗石头初始能量是E[i]E[i], 每秒钟增加L[i]L[i], 上限是C[i]C[i]

  • 区间收割MM次,求收割能量的总和

  • 收割时候会把区间里的能量都变为0

思路

分割时间

我们将时间分为两种

d[i]=(c[i]+l[i]1)/l[i]d[i] = (c[i] + l[i] - 1) / l[i],小心除0

大于d[i]d[i]的时间段数乘c[i]c[i]

小于d[i]d[i]的时间段数 乘 时间 乘 l[i]l[i]

树状数组维护单点的时间段

首先我们用树状数组维护一个点的时间段信息

一个树状数组维护时间段的个数,单点表示时长为ii的时间段个数有几个

query(d[i],maxn)c[i]query(d[i], maxn)* c[i]即为到达上限的答案

一个树状数组维护时间段和时间的乘积,单点表示时长为ii的时间段个数乘时间长度

query(1,d[i]1)l[i]query(1, d[i] - 1)* l[i]即为未达到上限的答案

区间修改

由于修改区间状态,l[i]r[i]l[i] - r[i]状态更改

那么我们在l[i]l[i]更改状态,在r[i]r[i]改回来即可

  • setset维护覆盖该点的收割区间,记录所有覆盖该点的收割时间

l[i]l[i]时加入收割时间,r[i]r[i]删除收割时间

  • 每加入一个新的收割时间

可能存在t2t2插入t1,t3中的情况(t1<t2<t3)(t1 < t2 < t3)

原本已经计算了t3t1t3-t1的时间段,将t3t1t3-t1删除

t2t1t2-t1t3t2t3-t2加入,反之亦然

  • 第一个收割时间即为初始能量增加的情况,特殊处理一下

代码

树状数组

	namespace Tree {
	const int maxn = 200005;
	const int limit = 200000;
	int tree[maxn];
	inline int lowbit(int x) {
		return x & -x;
	}
	void update(int x, int val) {	//维护时间段个数
		for (int i = x; i <= limit; i += lowbit(i)) tree[i] += val;
	}
	int query(int left, int right) {
		int res = 0;
		for (int i = right; i; i -= lowbit(i)) res += tree[i];
		for (int i = left - 1; i; i -= lowbit(i)) res -= tree[i];
		return res;
	}
	LL num_tree[maxn];
	void num_update(int x, int val) {	//维护时间段*时间总和
		for (int i = x; i <= limit; i += lowbit(i)) num_tree[i] += LL(x) * val;
	}
	LL num_query(int left, int right) {
		LL res = 0;
		for (int i = right; i; i -= lowbit(i)) res += num_tree[i];
		for (int i = left - 1; i; i -= lowbit(i)) res -= num_tree[i];
		return res;
	}
}

区间维护

for (int i = 1; i <= n; i++) {
	for (auto it : S[i]) {		//加入区间开始
		T.insert(it);
		auto iter = T.find(it);
		auto pre = iter, suf = iter;
		if (iter != T.begin())	//加入t2-t1
			Tree::update(*iter - *--pre, 1),
			Tree::num_update(*iter - *pre, 1);
		if (++suf != T.end())	//加入t3-t2
			Tree::update(*suf - *iter, 1),
			Tree::num_update(*suf - *iter, 1);
		if (iter != T.begin() && suf != T.end())	//删除t3-t1
			Tree::update(*suf - *pre, -1),
			Tree::num_update(*suf - *pre, -1);
	}
	if (T.size()) {
		auto iter = T.begin();		//第一个时间点为a[i]+t*l[i]的情况
		if (a[i] + LL(*iter) * l[i] >= c[i]) ans += LL(c[i]);
		else ans += LL(a[i]) + LL(*iter) * l[i];
		if (l[i])		//计算答案
			ans += LL(Tree::query(d[i], 200000)) * c[i],
			ans += LL(Tree::num_query(1, d[i] - 1)) * l[i];
	}
	for (auto it : E[i]) {
		auto iter = T.find(it);
		auto pre = iter, suf = iter;
		if (iter != T.begin())	//删除t2-t1
			Tree::update(*iter - *--pre, -1),
			Tree::num_update(*iter - *pre, -1);
		if (++suf != T.end())	//删除t3-t2
			Tree::update(*suf - *iter, -1),
			Tree::num_update(*suf - *iter, -1);
		if (iter != T.begin() && suf != T.end())	//加入t3-t1
			Tree::update(*suf - *pre, 1),
			Tree::num_update(*suf - *pre, 1);
		T.erase(it);
	}
}

AC

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <vector>
typedef long long LL;
using namespace std;
namespace Tree {
	const int maxn = 200005;
	const int limit = 200000;
	int tree[maxn];
	inline int lowbit(int x) {
		return x & -x;
	}
	void update(int x, int val) {
		for (int i = x; i <= limit; i += lowbit(i)) tree[i] += val;
	}
	int query(int left, int right) {
		int res = 0;
		for (int i = right; i; i -= lowbit(i)) res += tree[i];
		for (int i = left - 1; i; i -= lowbit(i)) res -= tree[i];
		return res;
	}
	LL num_tree[maxn];
	void num_update(int x, int val) {
		for (int i = x; i <= limit; i += lowbit(i)) num_tree[i] += LL(x) * val;
	}
	LL num_query(int left, int right) {
		LL res = 0;
		for (int i = right; i; i -= lowbit(i)) res += num_tree[i];
		for (int i = left - 1; i; i -= lowbit(i)) res -= num_tree[i];
		return res;
	}
}
const int maxn = 100005;
set<int> T;
int a[maxn], l[maxn], c[maxn], d[maxn];
int t[maxn], s[maxn], e[maxn];
vector<int> S[maxn], E[maxn];
int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);
	int __case, n, m; cin >> __case;
	for (int i = 1; i <= __case; i++) {
		cin >> n; T.clear();
		for (int i = 1; i <= n; i++) {
			cin >> a[i] >> l[i] >> c[i];
			if (l[i])d[i] = (c[i] + l[i] - 1) / l[i];
			S[i].clear(); E[i].clear();
		}
		cin >> m;
		for (int i = 1; i <= m; i++) {
			cin >> t[i] >> s[i] >> e[i];
			S[s[i]].push_back(t[i]);
			E[e[i]].push_back(t[i]);
		}
		LL ans = 0;
		for (int i = 1; i <= n; i++) {
			for (auto it : S[i]) {
				T.insert(it);
				auto iter = T.find(it);
				auto pre = iter, suf = iter;
				if (iter != T.begin())
					Tree::update(*iter - *--pre, 1),
					Tree::num_update(*iter - *pre, 1);
				if (++suf != T.end())
					Tree::update(*suf - *iter, 1),
					Tree::num_update(*suf - *iter, 1);
				if (iter != T.begin() && suf != T.end())
					Tree::update(*suf - *pre, -1),
					Tree::num_update(*suf - *pre, -1);
			}
			if (T.size()) {
				auto iter = T.begin();
				if (a[i] + LL(*iter) * l[i] >= c[i]) ans += LL(c[i]);
				else ans += LL(a[i]) + LL(*iter) * l[i];
				if (l[i])
					ans += LL(Tree::query(d[i], 200000)) * c[i],
					ans += LL(Tree::num_query(1, d[i] - 1)) * l[i];
			}
			for (auto it : E[i]) {
				auto iter = T.find(it);
				auto pre = iter, suf = iter;
				if (iter != T.begin())
					Tree::update(*iter - *--pre, -1),
					Tree::num_update(*iter - *pre, -1);
				if (++suf != T.end())
					Tree::update(*suf - *iter, -1),
					Tree::num_update(*suf - *iter, -1);
				if (iter != T.begin() && suf != T.end())
					Tree::update(*suf - *pre, 1),
					Tree::num_update(*suf - *pre, 1);
				T.erase(it);
			}
		}
		cout << "Case #" << i << ": " << ans << '\n';
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章