有N个英雄,初始为1级,0经验。有M波怪物,每波怪物选择区间[l,r]的英雄去打,打死每波怪物的英雄会获得k(等级)*ei的经验,现在给出升到每个等级所需要的经验,和每波怪物派出的英雄,每次询问一个区间内经验值最高的值。
一道线段树区间更新变形题,容易想到每次更新对每个子区间的改变是不同的,但是,对答案的英雄却是唯一的,假设一个区间的最大等级为lv,那么更新当v前区间时,如果没有英雄升级,区间的答案满足,ans=ans+ei*lv,所以可以使用懒惰更新,如果有英雄升级,那么应当暴力更新到底,更新一次的复杂度为logn。k<=10,那么每个点修改的次数不超过10,所以整体复杂度为k*nlogn,是满足要求的。
#include
#include
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;
}