CF1320C - World of Darkraft: Battle for Azathoth 思维+线段树

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值