牛客網暑期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';
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章