标签:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3954 , 一道比较好的线段树题,值得做。
题目是NotOnlySuccess大神出的,借此题来膜拜一下大神,毕竟我学的就是NotOnlySuccess线段树,ORZ。
这道题比较复杂,如何判断一波经验加成之后是否有英雄需要升级,如果升级需要如何处理,怎样维护Exp的区间最值,都是这道题的难点。
我在网上百度了别人的题解才收到的启发,具体方法如下:
线段树上三个数组:level[]表示等级的区间最值;Exp[]表示经验的区间最值; Min标记表示最少需要多少经验基数使该区间有英雄可以升级(刷怪得到的经验 = e * 等级,e就是经验基数)。
可知每个区间的等级最高的英雄其经验值也是最高的,所以对于每次更新,Exp[rt] += level[rt] * e。对于每次更新,如果当前区间有英雄可以升级,即 e >= Min[rt],那么就把这个区间实行点更新,枚举每个叶子节点检查英雄是否需要升级,英雄升级以后要更新Min标记;如果没有英雄升级,就进行正常的区间更新(更新Min标记,更新Exp值)。
#include <iostream>
#include <cstdio>
#include <vector>
#include <cmath>
#include <string>
#include <string.h>
#include <algorithm>
using namespace std;
#define LL __int64
#define eps 1e-8
#define INF INT_MAX
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
const int MOD = 10000007;
const int maxn = 10000 + 5;
const int N = 12;
int level[maxn << 2] , Exp[maxn << 2] , col[maxn << 2];
double Min[maxn << 2];
int Need[N];
void PushUp(int rt)
{
level[rt] = max(level[rt << 1] , level[rt << 1 | 1]);
Exp[rt] = max(Exp[rt << 1] , Exp[rt << 1 | 1]);
Min[rt] = min(Min[rt << 1] , Min[rt << 1 | 1]);
}
void PushDown(int rt)
{
if(col[rt]) {
col[rt << 1] += col[rt];
col[rt << 1 | 1] += col[rt];
Min[rt << 1] -= col[rt];
Min[rt << 1 | 1] -= col[rt];
Exp[rt << 1] += level[rt << 1] * col[rt];
Exp[rt << 1 | 1] += level[rt << 1 | 1] * col[rt];
col[rt] = 0;
}
}
void build(int l , int r , int rt)
{
if(l == r) {
level[rt] = 1;
Exp[rt] = 0;
Min[rt] = Need[2] * 1.0;
return;
}
col[rt] = 0;
int m = (l + r) >> 1;
build(lson);
build(rson);
PushUp(rt);
}
void level_up(int e , int l , int r , int rt)
{
if(l == r) { //更新到叶子节点
Exp[rt] += e * level[rt];
while(Exp[rt] >= Need[level[rt] + 1])
level[rt]++; //升级英雄
Min[rt] = (Need[level[rt] + 1] - Exp[rt]) * 1.0 / level[rt]; //更新Min标记
return;
}
PushDown(rt);
int m = (l + r) >> 1;
level_up(e , lson);
level_up(e , rson);
PushUp(rt);
}
void update(int L , int R , int e , int l , int r , int rt)
{
if(l == r) {
Exp[rt] += e * level[rt];
while(Exp[rt] >= Need[level[rt] + 1])
level[rt]++;
Min[rt] = (Need[level[rt] + 1] - Exp[rt]) * 1.0 / level[rt];
return;
}
if(L <= l && R >= r) {
if(Min[rt] - e > 0.00) { //没有英雄升级
Min[rt] -= e;
col[rt] += e;
Exp[rt] += level[rt] * e;
} else { //有英雄升级
PushDown(rt);
level_up(e , l , r , rt);
PushUp(rt);
}
return;
}
PushDown(rt);
int m = (l + r) >> 1;
if(L > m)
update(L , R , e , rson);
else if(R <= m)
update(L , R , e , lson);
else {
update(L , R , e , lson);
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 Exp[rt];
}
PushDown(rt);
int m = (l + r) >> 1;
if(L > m)
return query(L , R , rson);
else if(R <= m)
return query(L , R , lson);
else
return max(query(L , R , lson) , query(L , R , rson));
}
int main()
{
int T , K , n , m , i , a , b , c;
char ch[3];
cin >> T;
for(int k = 1 ; k <= T ; k++)
{
printf("Case %d:\n" , k);
scanf("%d %d %d" , &n , &K , &m);
for(i = 2 ; i <= K ; i++)
scanf("%d" , &Need[i]);
Need[i] = INF;
build(1 , n , 1);
while(m--) {
scanf("%s" , ch);
if(ch[0] == ‘W‘) {
scanf("%d %d %d" , &a , &b , &c);
update(a , b , c , 1 , n , 1);
} else if(ch[0] == ‘Q‘) {
scanf("%d %d" , &a , &b);
printf("%d\n" , query(a , b , 1 , n , 1));
}
}
puts("");
}
return 0;
}
标签:
原文地址:http://www.cnblogs.com/H-Vking/p/4297983.html