HDU3954 线段树(区间更新 + 点更新)

  题目链接: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:
" , 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
" , query(a , b , 1 , n , 1));
            }
        }
        puts("");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/H-Vking/p/4297983.html