题解
题意:一排n个1级英雄打怪兽吃经验升级,告诉你每个等级所需的经验值,升级不掉经验值,再给两个操作:
W l r e
每一波怪兽,派出[l,r]区间内的英雄去打,干掉这波怪兽,每个英雄可以获得 自身等级*e 点经验值Q l r
询问[l,r]区间内最高的经验值
很明显的线段树,但是更新好难啊…
看了别人的代码,现在来补补题,
由于每次获得经验都是跟英雄自身等级有关,要么暴力更新 不用尝试了,我试过,TLE了
要么添加一个懒标记,等区间内有英雄要升级时,再暴力更新
现在,定义懒标记need[]
表示:
区间内距离下一次升级最小的 所需的经验值 与 英雄等级 之比,
这个比值是什么?
是怪兽提供的 e,
这样一来,区间维护就和英雄的等级没有关系啦,
大致方法如下:
- 每来一波怪兽,累加e值,用
all[]
维护, - 每来一波怪兽,区间最大经验值应该是 原先最大的经验值 + 区间内最高的等级 * 新增的e值,(连续升级也是用原先的等级累加的),用
ekp[]
维护区间最大经验值 - 如果累加的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;
}