• 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;
    }
  • 相关阅读:
    [Usaco2008 Nov]mixup2 混乱的奶牛
    [Poi2004] 旅行问题
    [洛谷P1278]单词游戏
    redis20
    redis19
    redis18
    OHC Java堆外缓存详解与应用
    SQL优化
    Mysql安装、字符、引擎设置
    大文件下载
  • 原文地址:https://www.cnblogs.com/H-Vking/p/4297983.html
Copyright © 2020-2023  润新知