HDU_3954
一开始始终在纠结要怎样维护max,因为不同等级的人每次加的经验是不一样的,这样如果只用一个max来维护最大值的话是很难办的。看了胡浩的出题报告之后恍然大悟,既然一个max来维护是很难办的,那不妨就将max变成K个,max[i]表示等级为i的人的经验的最大值,这样max[i]的增加就很好处理了。
至于如何处理一个人的升级问题,既然有了max[i],那么我们就知道每个等级上是否有人的经验达到了need[i+1],一旦有人达到就直接找到这个人,并将路径上的max[i]和max[i+1]的值更新一下即可。由于K比较小,每个人最多升级K次,而每次找一个人的复杂度是logN,所以升级操作总的复杂度是K*N*logN,是可以接受的。查询操作就比较好写了。
#include<stdio.h> #include<string.h> #define MAXD 10010 #define MAXK 11 #define INF 0x3f3f3f3f int N, K, QW, max[4 * MAXD][MAXK], add[4 * MAXD], need[MAXK]; void build(int cur, int x, int y) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; memset(max[cur], -1, sizeof(max[cur])); max[cur][1] = add[cur] = 0; if(x == y) return ; build(ls, x, mid); build(rs, mid + 1, y); } void init() { int i; scanf("%d%d%d", &N, &K, &QW); for(i = 1; i < K; i ++) scanf("%d", &need[i]); need[K] = INF; build(1, 1, N); } int getmax(int x, int y) { return x > y ? x : y; } void update(int cur) { int i, ls = cur << 1, rs = (cur << 1) | 1; for(i = 1; i <= K; i ++) max[cur][i] = getmax(max[ls][i], max[rs][i]); } void pushdown(int cur) { int ls = cur << 1, rs = (cur << 1) | 1; if(add[cur]) { int i; add[ls] += add[cur], add[rs] += add[cur]; for(i = 1; i <= K; i ++) { if(max[ls][i] != -1) max[ls][i] += i * add[cur]; if(max[rs][i] != -1) max[rs][i] += i * add[cur]; } add[cur] = 0; } } void change(int cur, int x, int y, int k) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; if(x == y) { max[cur][k + 1] = max[cur][k]; max[cur][k] = -1; return ; } pushdown(cur); if(max[ls][k] >= need[k]) change(ls, x, mid, k); else change(rs, mid + 1, y, k); max[cur][k] = getmax(max[ls][k], max[rs][k]); max[cur][k + 1] = getmax(max[ls][k + 1], max[rs][k + 1]); } void refresh(int cur, int x, int y, int s, int t, int delta) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; if(x >= s && y <= t) { int i; add[cur] += delta; for(i = 1; i <= K; i ++) if(max[cur][i] != -1) max[cur][i] += i * delta; for(i = 1; i < K; i ++) while(max[cur][i] >= need[i]) change(cur, x, y, i); return ; } pushdown(cur); if(mid >= s) refresh(ls, x, mid, s, t, delta); if(mid + 1 <= t) refresh(rs, mid + 1, y, s, t, delta); update(cur); } void query(int cur, int x, int y, int s, int t, int &ans) { int mid = (x + y) >> 1, ls = cur << 1, rs = (cur << 1) | 1; if(x >= s && y <= t) { int i; for(i = 1; i <= K; i ++) if(max[cur][i] > ans) ans = max[cur][i]; return ; } pushdown(cur); if(mid >= s) query(ls, x, mid, s, t, ans); if(mid + 1 <= t) query(rs, mid + 1, y, s, t, ans); } void solve() { int i, j, k, x, y, z, ans; char b[5]; for(i = 0; i < QW; i ++) { scanf("%s", b); if(b[0] == 'W') { scanf("%d%d%d", &x, &y, &z); refresh(1, 1, N, x, y, z); } else { scanf("%d%d", &x, &y); ans = 0; query(1, 1, N, x, y, ans); printf("%d\n", ans); } } } int main() { int t, tt; scanf("%d", &t); for(tt = 0; tt < t; tt ++) { init(); printf("Case %d:\n", tt + 1); solve(); printf("\n"); } return 0; }