题目大意:
事件分为两类:战役事件
CASE
C
A
S
E
和穿越回去事件
END
E
N
D
。
战役事件可以选择是否参加,参加后会获得一定金钱。
END事件发生需要至少参加一定数量的战役事件。
特别的是,END事件如果满足要求就会强制发生。
要求只有最后一个END事件会发生。
问此时获得最多的金钱数,无法满足则输出
−1
−
1
N<=200,000
N
<=
200
,
000
每次赏金不超过
10,000
10
,
000
穿越事件的要求不超过
200,000
200
,
000
分析:
将
END
E
N
D
事件的要求限制成一个满足要求的递增序列,
即除了最后一个,其他的都满足前面
<=
<=
<script type="math/tex" id="MathJax-Element-122"><=</script>后面,
然后维护一个满足要求的小根堆即可。
最后判断堆中元素个数,如果没有>=最后一个END的要求则无解,否则计算堆中元素总和即为答案。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define N 200005
using namespace std;
struct Node {
int x, id;
friend bool operator < (Node aa, Node bb)
{
return aa.x > bb.x;
}
}a[N];
struct Code { int x, id; }b[N];
priority_queue <Node> Q;
char str[10];
int ans, last, cnt, tot, n;
int main()
{
freopen("data.in","r",stdin);
scanf("%d", &n);
last = 0;
for (int i = 1; i <= n; i++)
{
scanf("%s", str);
if (str[0] == 'c')
{
scanf("%d", &a[++cnt].x);
a[cnt].id = i;
}
else
{
scanf("%d", &b[++tot].x);
b[tot].id = i;
}
}
int now = b[tot - 1].x;
for (int i = tot - 2; i >= 1; i--)
if (b[i].x > now) b[i].x = now;
else now = min(now, b[i].x);
int l1 = 1, l2 = 1;
while (l1 <= cnt && l2 <= tot - 1)
{
while (l1 <= cnt && a[l1].id <= b[l2].id)
{
if (Q.size() < b[l2].x - 1) Q.push(a[l1]);
else
{
if (Q.size() != 0)
if (a[l1].x > Q.top().x)
{
Q.pop();
Q.push(a[l1]);
}
}
l1++;
}
l2++;
}
for (int i = l1; i <= cnt; i++) Q.push(a[i]);
if (Q.size() < b[tot].x) printf("-1\n");
else
{
int ans = 0;
while (Q.size())
{
ans += Q.top().x;
Q.pop();
}
printf("%d\n", ans);
}
return 0;
}