hdu 3954 Level up· 线段树

题解

题意:一排n个1级英雄打怪兽吃经验升级,告诉你每个等级所需的经验值,升级不掉经验值,再给两个操作:

  1. W l r e每一波怪兽,派出[l,r]区间内的英雄去打,干掉这波怪兽,每个英雄可以获得 自身等级*e 点经验值
  2. Q l r询问[l,r]区间内最高的经验值

很明显的线段树,但是更新好难啊…

看了别人的代码,现在来补补题,

由于每次获得经验都是跟英雄自身等级有关,要么暴力更新 不用尝试了,我试过,TLE了
要么添加一个懒标记,等区间内有英雄要升级时,再暴力更新

现在,定义懒标记need[]表示:
区间内距离下一次升级最小所需的经验值 与 英雄等级 之比

这个比值是什么?
是怪兽提供的 e,
这样一来,区间维护就和英雄的等级没有关系啦,

大致方法如下:

  1. 每来一波怪兽,累加e值,用all[]维护,
  2. 每来一波怪兽,区间最大经验值应该是 原先最大的经验值 + 区间内最高的等级 * 新增的e值,(连续升级也是用原先的等级累加的),用ekp[]维护区间最大经验值
  3. 如果累加的e值,足够区间内某一个英雄升级,即 all ≥ \ge e,就向下更新子区间,更新英雄的等级,经验在第二步就已经更新过了,并且因为涉及到向上更新,单点更新和区间更新又是不一样的,需要区分

哦对了need[]向上取整


在这里插入图片描述


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
int n, m, k;

int Needk[N];
namespace seg_tree {//线段树板子

    int ekp[N * 4];//维护最大的经验值
    int all[N * 4];//总共下放的怪物e值
    int need[N * 4];//所需e值(经验/等级) 
    int rank[N * 4];//最大等级

    void pushdown(int l, int r, int rt);

    void levelup(int rt) {
        all[rt] = 0;
        while (ekp[rt] >= Needk[rank[rt] + 1]) rank[rt]++;
        int tmp = Needk[rank[rt] + 1] - ekp[rt];//下一级升级经验
        need[rt] = tmp / rank[rt] + (tmp % rank[rt] ? 1 : 0);
        //也可以 用函数 ceil() 向上取整
    }

    void pushup(int rt) {
        ekp[rt] = max(ekp[rt << 1], ekp[rt << 1 | 1]);
        rank[rt] = max(rank[rt << 1], rank[rt << 1 | 1]);
        need[rt] = min(need[rt << 1], need[rt << 1 | 1]);
    }

    void maintain(int l, int r, int rt, int e) {
        need[rt] -= e;
        all[rt] += e;
        ekp[rt] += rank[rt] * e;
        if (need[rt] <= 0) {
            if (l == r) levelup(rt);//单点修改等级
            else {
                pushdown(l, r, rt);//区间修改
                pushup(rt);
            }
        }
    }

    void pushdown(int l, int r, int rt) {
        if (all[rt]) {
            int mid = l + r >> 1;
            maintain(l, mid, rt << 1, all[rt]);//下放怪物
            maintain(mid + 1, r, rt << 1 | 1, all[rt]);
            all[rt] = 0;
        }
    }

    void build(int l, int r, int rt) {
        ekp[rt] = all[rt] = need[rt] = rank[rt] = 0;
        if (l == r) {
            rank[rt] = 1;
            need[rt] = Needk[2];
            return;
        }
        int mid = l + r >> 1;
        build(lson);
        build(rson);
        pushup(rt);
    }

    void update(int L, int R, int e, int l, int r, int rt) {
        if (L <= l && r <= R) {
            maintain(l, r, rt, e);
            return;
        }
        int mid = l + r >> 1;
        pushdown(l, r, rt);
        if (L <= mid) update(L, R, e, lson);
        if (R > mid) update(L, R, e, rson);
        pushup(rt);
    }

    int query(int L, int R, int l, int r, int rt) {
        if (L <= l && r <= R) {
            return ekp[rt];
        }
        int mid = l + r >> 1;
        pushdown(l, r, rt);
        int res = 0;
        if (L <= mid)res = max(res, query(L, R, lson));
        if (R > mid)res = max(res, query(L, R, rson));
        pushup(rt);
        return res;
    }
}
using namespace seg_tree;

string op;
int main() {
    ios::sync_with_stdio(0);

    int T;
    cin>>T;

    for (int cs = 1; cs <= T; ++cs) {
        printf("Case %d:\n", cs);

       	cin>>n>>k>>m;
        for (int i = 2; i <= k; ++i) {
            cin>>Needk[i];
        }
        Needk[k + 1] = INF;
        build(1, n, 1);

        for (int i = 1, l, r, e; i <= m; ++i) {
            cin>>op>>l>>r;
            if (op== "W") {
               	cin>>e;
                update(l, r, e, 1, n, 1);
            } else {
                printf("%d\n", query(l, r, 1, n, 1));
            }
        }
        puts("");//格式要求
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值