Energy stones
題意
-
每顆石頭初始能量是, 每秒鐘增加, 上限是
-
區間收割次,求收割能量的總和
-
收割時候會把區間裏的能量都變爲0
思路
分割時間
我們將時間分爲兩種
令,小心除0
大於的時間段數乘
小於的時間段數 乘 時間 乘
樹狀數組維護單點的時間段
首先我們用樹狀數組維護一個點的時間段信息
一個樹狀數組維護時間段的個數,單點表示時長爲的時間段個數有幾個
即爲到達上限的答案
一個樹狀數組維護時間段和時間的乘積,單點表示時長爲的時間段個數乘時間長度
即爲未達到上限的答案
區間修改
由於修改區間狀態,狀態更改
那麼我們在更改狀態,在改回來即可
- 用維護覆蓋該點的收割區間,記錄所有覆蓋該點的收割時間
時加入收割時間,刪除收割時間
- 每加入一個新的收割時間
可能存在插入t1,t3
中的情況
原本已經計算了的時間段,將刪除
將和加入,反之亦然
- 第一個收割時間即爲初始能量增加的情況,特殊處理一下
代碼
樹狀數組
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';
}
}