题意:
给定一段区间 [1, n],每个点都有自身的 Level 值和 Exp 值;
进行若干次操作 W 和 Q,
W L R e:给区间 [L, R] 的每个点增加一定的经验 exp = Level * e, 注意到每个点增加的经验值是不同的,与各自的等级成正比
Q L R:询问区间 [L, R] 内的最大经验值 maxExp
思考过程:
因为每个点增加的经验值是不同的,所以很难直接对区间整体进行操作,所以像普通的 lazy tag 一样给区间整体的 sum 加上 val * len 的值,再给区间整体的 tag 加上 val 值是不可行的。而且 tag 还不能简单地叠加,因为也许这次操作完有一个点就升级了呢?而且向上 push_up 的话每一段区间的 Level 值 与 Exp 值也意义不明,毕竟每个点都不一样啊..........
于是一开始就傻乎乎地写成了单点修改,然后TLE不解释............
看了 http://blog.youkuaiyun.com/wsniyufang/article/details/6702560 后,豁然开朗
我们思考下放 tag 的条件:一旦该区间内有一个点升级,就下放 tag
再考虑 tag 的意义,tag 代表了一个区间整体的性质,这才使得整体的操作成为可能。
那么在这道题里,区间整体有什么性质呢?事实上,我们可以用 rem(ain) 记录每个点还差多少经验 e 即可升级,整个区间的 rem 取所有点的 rem 的最小值,一旦给这段区间加上的 exp 超过 rem 值,即下放 tag
那么如果这次操作不能使得这段区间的任何一个点升级呢?显然,我们不需要下放 tag,而是需要在现有的 tag 值上加上这次的 exp。再仔细想想,如果我下次恰好询问的就是该区间内的 maxExp 呢?那么按照我们写 query 的格式,会直接返回这一段的经验最大值。所以,这经验最大值不应该简简单单地只是每一次从下面 push 上来的整个区间内的 maxExp 这个数值(因为如果更新 exp 的途径只是从下面 push 上来,在这种情况下,返回的值就是没有更新过的旧值),而还应该具有其自身的含义——那就是这个区间内经验最大的那个点的经验值,即它要代表这个区间内经验最大的那个点。
好像说的是同一码事,事实上还是有差别的,如果其意义为 这个区间内经验最大的那个点的经验值,即它代表了这个区间内经验最大的那个点(同时也必然是等级最高的那个点),那么 对这一段整体经验值的增加 导致的 该段经验值最大的点的经验的增加 就直接可以通过 对该区间记录的 exp 值的修改反应出来。
总结一下我们上面说的,每个区间的 exp 与 lv 值就应该是该区间内 exp 值 最大的点的 exp 值 与 lv 值,它就完完全全地反应了作为了那个点的代言人存在。
这样一来,对于每种情况该如何处理也差不多清楚了,就可以写代码了............
AC代码如下:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define maxn 10010
#define lson (rt << 1)
#define rson (rt << 1 | 1)
typedef long long LL;
struct node {
int l, r, lv, rem;
LL exp, tag;
}tr[maxn * 4];
int ned[20], n, k, q, kas;
inline LL max(LL a, LL b) { return a > b ? a : b; }
inline int max(int a, int b) { return a > b ? a : b; }
inline int midi(int a, int b) { return (a + b) >> 1; }
inline int min(int a, int b) { return a < b ? a : b; }
void push_up(int rt) {
tr[rt].exp = max(tr[lson].exp, tr[rson].exp);
tr[rt].rem = min(tr[lson].rem, tr[rson].rem);
tr[rt].lv = max(tr[lson].lv, tr[rson].lv);
}
void push_down(int rt) {
if (tr[rt].tag) {
tr[lson].exp += (LL)tr[lson].lv * tr[rt].tag;
tr[rson].exp += (LL)tr[rson].lv * tr[rt].tag;
tr[lson].rem -= tr[rt].tag; tr[rson].rem -= tr[rt].tag;
tr[lson].tag += tr[rt].tag; tr[rson].tag += tr[rt].tag;
tr[rt].tag = 0;
}
}
void build(int rt, int l, int r) {
tr[rt].l = l; tr[rt].r = r; tr[rt].exp = 0; tr[rt].tag = 0; tr[rt].lv = 0;
if (l == r) {
tr[rt].lv = 1;
tr[rt].rem = ned[1] / 1;
return;
}
int mid = midi(l, r);
build(lson, l, mid);
build(rson, mid + 1, r);
push_up(rt);
}
void modify(int rt, int l, int r, int exp) {
if (tr[rt].l == tr[rt].r) {
tr[rt].exp += (LL)exp * tr[rt].lv;
while (tr[rt].lv < k && tr[rt].exp >= ned[tr[rt].lv]) ++tr[rt].lv;
if (tr[rt].lv == k) tr[rt].rem = inf;
else tr[rt].rem = ceil((double)(ned[tr[rt].lv] - tr[rt].exp) / tr[rt].lv);
return;
}
if (tr[rt].l == l && tr[rt].r == r) {
if (tr[rt].rem > exp) {
tr[rt].exp += tr[rt].lv * exp;
tr[rt].tag += exp;
tr[rt].rem -= exp;
return;
}
push_down(rt);
int mid = midi(l, r);
modify(lson, l, mid, exp);
modify(rson, mid + 1, r, exp);
push_up(rt);
return;
}
push_down(rt);
int mid = midi(tr[rt].l, tr[rt].r);
if (r <= mid) modify(lson, l, r, exp);
else if (l > mid) modify(rson, l, r, exp);
else { modify(lson, l, mid, exp); modify(rson, mid + 1, r, exp); }
push_up(rt);
return;
}
LL query(int rt, int l, int r) {
if (tr[rt].l == l && tr[rt].r == r) return tr[rt].exp;
push_down(rt);
int mid = midi(tr[rt].l, tr[rt].r);
if (r <= mid) return query(lson, l, r);
else if (l > mid) return query(rson, l, r);
else return max(query(lson, l, mid), query(rson, mid + 1, r));
}
void work() {
printf("Case %d:\n", ++kas);
scanf("%d%d%d", &n, &k, &q);
for (int i = 1; i < k; ++i) scanf("%d", &ned[i]);
build(1, 1, n);
while (q--) {
char ch;
scanf("\n%c", &ch);
int l, r, exp;
if (ch == 'Q') {
scanf("%d%d", &l, &r);
printf("%lld\n", query(1, l, r));
}
else {
scanf("%d%d%d", &l, &r, &exp);
modify(1, l, r, exp);
}
}
printf("\n");
}
int main() {
// freopen("3954.in", "r", stdin);
int T;
scanf("%d", &T);
while (T--) work();
return 0;
}