http://codeforces.com/contest/1398

E. Two Types of Spells

 

题意:两种咒语:fire可以造成 did_i 伤害,lightning可以造成 did_i 伤害并且使下一个咒语伤害翻倍。初始咒语集合为空,n 次,每次向集合中添加或删除一个fire或lightning,问每次修改后用集合中咒语最多造成的伤害。

模拟

策略还是比较直接的:假设集合中有 c1 个lightning,则把前 c1 大个咒语翻倍。但是要注意如果前 c1 个包含了所有lightning,则无法全部翻倍,必须放弃一个最小的lightning,再另选一个。

维护两个set,第一个维护前c1大的咒语,第二个维护剩下的。

每次操作后需要更新这两个set,此时先不考虑“lightning不能全翻倍”这一限制,在取答案时再考虑。就类似维护堆,如果插入一个数,判断如果这个数大于第一个set中最小的,则它会代替最小的,所以要把这个数插入第一个set;否则插入第二个。再根据新的c1值,删除或增加set。

要注意并不是直接插到第二个set里就好了,必须判断能否插入第一个set,否则会使得它被忽略。经常手写堆的应该就不会犯这种错了。

再考虑取答案,还要再维护一个所有lightning咒语的set,判断如果最小的lightning都在第一个set里,那么所有lightning必定都在第一个set里了,这就是我们的限制,此时需要从答案中扣去最小的lightning,加上第二个set中的最大值。

还要注意两个set里维护的是当前所有可用的咒语,在添加删除或从一个set移到另一个里时要记得更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
const ll mod = 1e9 + 7;
int n;
int c1;
set<int>once, twice, lig;
ll sum, sum2;
void cg() {
while ((int)twice.size() > c1) {
sum2 -= *twice.begin();
once.insert(*twice.begin());
twice.erase(twice.begin());
}
while ((int)twice.size() < c1) {
sum2 += *once.rbegin();
twice.insert(*once.rbegin());
once.erase(*once.rbegin());
}
}
void ins(int d) {
sum += d;
if (twice.empty() || d < *twice.begin())once.insert(d);
else twice.insert(d), sum2 += d;
cg();
}
void del(int d) {
sum -= d;
if (twice.count(d)) {
sum2 -= d;
twice.erase(d);
}
else {
once.erase(d);
}
cg();
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
int tp, d;
scanf("%d%d", &tp, &d);
if (tp == 0) {
if (d > 0) {
ins(d);
}
else {
d = -d;
del(d);
}
}
else {
if (d > 0) {
c1++;
ins(d);
lig.insert(d);
}
else {
d = -d;
c1--;
del(d);
lig.erase(d);
}
}
ll ans = sum + sum2;
if (c1&&*lig.begin() >= *twice.begin()) {
ans -= *lig.begin();
if (!once.empty())ans += *once.rbegin();
}
printf("%lld\n", ans);
}
return 0;
}