HUD3954-Level up(线段树技巧)

题目大意:

有N个英雄,初始为1级,0经验。有M波怪物,每波怪物选择区间[l,r]的英雄去打,打死每波怪物的英雄会获得k(等级)*ei的经验,现在给出升到每个等级所需要的经验,和每波怪物派出的英雄,每次询问一个区间内经验值最高的值。


思路:

一道线段树区间更新变形题,容易想到每次更新对每个子区间的改变是不同的,但是,对答案的英雄却是唯一的,假设一个区间的最大等级为lv,那么更新当v前区间时,如果没有英雄升级,区间的答案满足,ans=ans+ei*lv,所以可以使用懒惰更新,如果有英雄升级,那么应当暴力更新到底,更新一次的复杂度为logn。k<=10,那么每个点修改的次数不超过10,所以整体复杂度为k*nlogn,是满足要求的。


AC代码:

#include <stdio.h>
#include <algorithm>

using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const ll INF = 1e15;
const ll maxn = 1e5 + 10;
struct node {
    ll lv;
    ll min_dif;//当前区间升级所需要的最小ei
    ll max_exp;
    ll flag;
} t[8 * maxn];
ll n, k, m;
ll needexp[maxn];

void pushup(ll root) {
    t[root].min_dif = min(t[root << 1].min_dif, t[root << 1 | 1].min_dif);
    t[root].max_exp = max(t[root << 1].max_exp, t[root << 1 | 1].max_exp);
    t[root].lv = max(t[root << 1].lv, t[root << 1 | 1].lv);
}

void build(ll l, ll r, ll root) {
    t[root].max_exp = 0;
    t[root].min_dif = 0;
    t[root].flag = 0;
    t[root].lv = 0;
    if (l == r) {
        t[root].lv = 1;
        t[root].max_exp = 0;
        t[root].min_dif = needexp[2];
        return;
    }
    ll mid = (l + r) / 2;
    build(l, mid, root << 1);
    build(mid + 1, r, root << 1 | 1);
    pushup(root);
}

void pushdown(ll root) {
    t[root << 1].min_dif -= t[root].flag;
    t[root << 1].max_exp += t[root].flag * t[root << 1].lv;
    t[root << 1].flag += t[root].flag;
    t[root << 1 | 1].min_dif -= t[root].flag;
    t[root << 1 | 1].max_exp += t[root].flag * t[root << 1 | 1].lv;
    t[root << 1 | 1].flag += t[root].flag;
    t[root].flag = 0;
}

void upans(ll l, ll r, ll root) {//更新到根,也要使用懒惰更新
    if (l == r) {
        while (t[root].max_exp >= needexp[t[root ].lv + 1]) t[root].lv++;
        t[root].min_dif = (needexp[t[root].lv + 1] - t[root].max_exp) / t[root].lv +
                          ((needexp[t[root].lv + 1] - t[root].max_exp) % t[root].lv == 0 ? 0 : 1);
        return;
    }
    pushdown(root);
    ll mid = (l + r) / 2;
    if (t[root << 1].min_dif <= 0) upans(l, mid, root << 1);
    if (t[root << 1 | 1].min_dif <= 0) upans(mid + 1, r, root << 1 | 1);
    pushup(root);
}

void update(ll l, ll r, ll nl, ll nr, ll root, ll val) {
    if (l == nl && r == nr) {
        t[root].min_dif -= val;
        t[root].flag += val;
        t[root].max_exp += val * t[root].lv;
        if (t[root].min_dif <= 0) upans(l, r, root);
        return;
    }
    pushdown(root);
    ll mid = (l + r) / 2;
    if (nr <= mid) update(l, mid, nl, nr, root << 1, val);
    else if (nl > mid) update(mid + 1, r, nl, nr, root << 1 | 1, val);
    else update(l, mid, nl, mid, root << 1, val), update(mid + 1, r, mid + 1, nr, root << 1 | 1, val);
    pushup(root);
}

ll query(ll l, ll r, ll nl, ll nr, ll root) {
    if (l == nl && r == nr)
        return t[root].max_exp;
    pushdown(root);
    ll mid = (l + r) / 2;
    if (nr <= mid) return query(l, mid, nl, nr, root << 1);
    else if (nl > mid) return query(mid + 1, r, nl, nr, root << 1 | 1);
    else return max(query(l, mid, nl, mid, root << 1), query(mid + 1, r,mid + 1, nr, root << 1 | 1));
}

int main() {
    ll tcase;
    scanf("%lld", &tcase);
    for (int s = 1; s <= tcase; s++) {
        scanf("%lld%lld%lld", &n, &k, &m);
        for (int i = 2; i <= k; i++) {
            scanf("%lld", &needexp[i]);
        }
        needexp[k + 1] = INF;
        build(1, n, 1);
        printf("Case %d:\n", s);
        for(int i = 0; i < m; i++) {
            char str[10];
            scanf("%s", str);
            if (str[0] == 'W') {
                ll l, r, ei;
                scanf("%lld%lld%lld", &l, &r, &ei);
                update(1, n, l, r, 1, ei);
            }else {
                ll l, r;
                scanf("%lld%lld", &l, &r);
                printf("%lld\n", query(1, n, l, r, 1));
            }
        }
        printf("\n");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/swust5120160705/article/details/81259442
HUD
今日推荐