CF1320C - World of Darkraft: Battle for Azathoth
题意
N
N
N个武器,
M
M
M个防具,
K
K
K个怪兽
每一个武器都有对应的攻击力
a
i
a_i
ai,还有购买它的金币数
c
a
i
ca_i
cai
每一个防具都有对应的防御力
b
i
b_i
bi,还有购买它的金币数
c
b
i
cb_i
cbi
每一个怪兽都有对应的攻击力
x
i
x_i
xi,防御力
y
i
y_i
yi,打败他获得的金币数
z
i
z_i
zi
如果现在持有武器和防具,只有在
a
>
x
i
,
b
>
y
i
a>x_i,b > y_i
a>xi,b>yi的情况下才能打败怪兽
i
i
i
现在各选一件武器和防具,使得获得的收益最大
题解
偏序问题,我先想到的就是排序
将怪兽按其攻击力
x
i
x_i
xi排序
这样扫到第
i
i
i个怪兽的时候,如果当前武器攻击力为
x
i
+
1
x_i+1
xi+1的话,前面的怪兽的攻击力都是小于
x
i
+
1
x_i+1
xi+1的
这样只需要看防御力是不是大于前面的怪兽就行
换个角度来想,一只防御力为
y
y
y的怪兽,只会对防御力为
[
y
+
1
,
1
0
6
]
[y+1,10^6]
[y+1,106]的防具有贡献
所以这里可以用线段树来维护每一个防御力的最大收益,区间更新操作维护最大值
初始值就是每一个防御力购买防具的最小花费
代码
#include <bits/stdc++.h>
using namespace std;
#define lc u<<1
#define rc u<<1|1
#define mid (t[u].l+t[u].r)/2
typedef long long ll;
typedef pair<int, int> pii;
const int MAX = 1e6 + 10;
const int tot = 1e6;
const ll inf = 1e18;
int N, M, K;
ll a[MAX], b[MAX];
vector<pii> g[MAX];
struct SegmentTree {
int l, r;
ll mx, tag;
void upd(ll k) {
mx += k;
tag += k;
}
} t[MAX << 2];
void push_up(int u) { t[u].mx = max(t[lc].mx, t[rc].mx); }
void push_down(int u) {
if (t[u].tag) {
t[lc].upd(t[u].tag);
t[rc].upd(t[u].tag);
t[u].tag = 0;
}
}
void build(int u, int l, int r) {
t[u] = SegmentTree{ l, r, -inf, 0 };
if (l == r) {
t[u].mx = -b[l];
return;
}
build(lc, l, mid);
build(rc, mid + 1, r);
push_up(u);
}
void update(int u, int ql, int qr, ll k) {
if (ql <= t[u].l && t[u].r <= qr) {
t[u].upd(k);
return;
}
push_down(u);
if (ql <= mid) update(lc, ql, qr, k);
if (qr > mid) update(rc, ql, qr, k);
push_up(u);
}
int main() {
scanf("%d%d%d", &N, &M, &K);
for (int i = 1; i < MAX; i++) a[i] = b[i] = inf;
for (int i = 1; i <= N; i++) {
int x, y; scanf("%d%d", &x, &y);
a[x] = min(a[x], 1ll * y);
}
for (int i = 1; i <= M; i++) {
int x, y; scanf("%d%d", &x, &y);
b[x] = min(b[x], 1ll * y);
}
for (int i = 1; i <= K; i++) {
int x, y, z; scanf("%d%d%d", &x, &y, &z);
g[x].push_back(make_pair(y, z));
}
build(1, 1, tot);
ll ans = -inf;
for (int i = 1; i <= tot; i++) {
ans = max(ans, t[1].mx - a[i]);
for (pii &j: g[i])
if (j.first + 1 <= tot)
update(1, j.first + 1, tot, j.second);
}
printf("%lld\n", ans);
return 0;
}