hdu 3954 Level up 线段树

Level up

Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3674    Accepted Submission(s): 994


Problem Description
Level up is the task of all online games. It's very boooooooooring. There is only level up in those games, except level up.
In a online game, there are N heroes numbered id from 1 to N, each begins with level 1 and 0 Experience. They need to kill monsters to get Exp and level up.

There are many waves of monsters, each wave, the heroes with id from li to ri will come to kill monsters and those hero with level k will get ei*k Exp. If one hero's Exp reach Needk then the hero level up to level k immediately.
After some waves, I will query the maximum Exp from li to ri.
Now giving the information of each wave and Needk, please tell me the answer of my query.
 

Input
The first line is a number T(1<=T<=30), represents the number of case. The next T blocks follow each indicates a case.
The first line of each case contains three integers N(1<=N<=10000), K(2<=K<=10) and QW(1<=QW<=10000)each represent hero number, the MAX level and querys/waves number.
Then a line with K -1 integers, Need2, Need3...Needk.(1 <= Need2 < Need3 < ... < Needk <= 10000).
Then QW lines follow, each line start with 'W' contains three integers li ri ei (1<=li<=ri<=N , 1<=ei<=10000); each line start with 'Q' contains two integers li ri (1<=li<=ri<=N).
 

Output
For each case, output the number of case in first line.(as shown in the sample output)
For each query, output the maximum Exp from li to ri.
Output a black line after each case.
 

Sample Input
  
  
2 3 3 5 1 2 W 1 1 1 W 1 2 1 Q 1 3 W 1 3 1 Q 1 3 5 5 8 2 10 15 16 W 5 5 9 W 3 4 5 W 1 1 2 W 2 3 2 Q 3 5 W 1 3 8 Q 1 2 Q 3 5
 

Sample Output
  
  
Case 1: 3 6 Case 2: 9 18 25
Hint
Case 1: At first ,the information of each hero is 0(1),0(1),0(1) [Exp(level)] After first wave, 1(2),0(1),0(1); After second wave, 3(3),1(2),0(1); After third wave, 6(3),3(3),1(2); Case 2: The information of each hero finally: 18(5) 18(5) 25(5) 5(2) 9(2)
 

Author
NotOnlySuccess


题目:

有很多英雄,有经验,可以升级,给两个操作。w,选择一个区间的英雄,增加经验经验是e*Level(指英雄的等级)

英雄的经验到了一定程度会升级,而且是立马升级到那个等级。

另外一个操作是q, 对l,r区间求经验最大的值。


分析:

     建立10课线段树。分别表示1-K等级。对于询问Q,把K棵树的最大值输出即可。

初始化,第1棵线段树的值都为0,其他线段树都是负无穷。对于W操作,对每棵树的l,r区间都增加对应的e*level值。由于如果影响不在这个等级上,增加任何值都还是负无穷,不用怕。

然后枚举k棵树,看看有没有英雄的经验大于这棵树的限制,如果有就把这个英雄升级到对应的等级中。然后把升级后对应的结点值设为它的经验值,原来树的英雄的经验值设置为负无穷。




#include<iostream>
#include<cstring>
#include<algorithm>
#include<set>
#include<cstdio>
using namespace std;
#define ll long long
#define maxn 400007
int lc[maxn],rc[maxn];
ll lz[maxn],ma[maxn];
int cnt;
ll inf = -10000000000ll;
void init(){
    lc[0] = rc[0] = 0;
    lz[0] = ma[0] = inf;
    cnt = 1;
}

void update(int u){
    if(rc[u] != 0)
        lz[rc[u]] += lz[u];
    if(lc[u] != 0)
        lz[lc[u]] += lz[u];
    lz[u] = 0;
    ma[u] = inf;
    if(rc[u] != 0)
        ma[u] = max(ma[u],ma[rc[u]]+lz[rc[u]]);
    if(lc[u] != 0)
        ma[u] = max(ma[u],ma[lc[u]]+lz[lc[u]]);
}

void build(int u,int l,int r,ll v){
    lz[u] = ma[u] = 0;
    if(l == r){
        lc[u] = rc[u] = 0;
        lz[u]  = v;
        ma[u] = 0;
        return ;
    }
    int mid = (l+r)/2;
    lc[u] = cnt++;
    rc[u] = cnt++;
    build(lc[u],l,mid,v);
    build(rc[u],mid+1,r,v);
    update(u);
}

void add(int u,int l,int r, int L, int R,ll v){
    if(L == l && R == r){
        lz[u] += v;
        return ;
    }
    int mid = (l+r)/2;
    if(mid >= R)
        add(lc[u],l,mid,L,R,v);
    else if(mid < L)
        add(rc[u],mid+1,r,L,R,v);
    else add(lc[u],l,mid,L,mid,v), add(rc[u],mid+1,r,mid+1,R,v);
    update(u);
}

ll query(int u,int l,int r,int L,int R){
    if(L == l && R == r){
        return lz[u] + ma[u];
    }
    update(u);
    ll ans ;
    int mid = (l+r)/2;
    if(mid >= R)
        ans = query(lc[u],l,mid,L,R);
    else if(mid < L)
        ans = query(rc[u],mid+1,r,L,R);
    else ans = max(query(lc[u],l,mid,L,mid), query(rc[u],mid+1,r,mid+1,R));
    update(u);
    return ans;
}
//寻找一个结点值等于v的结点号
int find(int u,int l,int r,ll v){
    if(l == r){
        return l;
    }
    int mid = (l+r)/2;
    update(u);
    int c1 = lc[u];
    if(ma[c1] + lz[c1] == v)
        return find(c1,l,mid,v);
    return find(rc[u],mid+1,r,v);
}
//把结点p设置为v值
void sett(int u,int l,int r,int p,ll v){
    if( l == r){
        lz[u] = v;
        return ;
    }
    update(u);
    int mid = (l+r)/2;
    if(p > mid)
        sett(rc[u],mid+1,r,p,v);
    else sett(lc[u],l,mid,p,v);
    update(u);
}


int k;
int leve[maxn];
int need[20];
int tree[20];
int main(){
    int t,n,q;
    scanf("%d",&t);
    for(int tt = 1; tt <= t; tt++){
        scanf("%d%d%d",&n,&k,&q);
        for(int i = 1;i < k; i++)
            scanf("%d",&need[i]);
        init();
//初始化建树
        for(int i = 1;i <= k; i++){
            tree[i] = cnt++;
            if(i == 1)
                build(tree[i],1,n,0);
            else build(tree[i],1,n,inf);
        }
        char x[2];
        int l,r,e;
        printf("Case %d:\n",tt);
        while(q--){
            scanf("%s",x);
            if(x[0] == 'W'){
                scanf("%d%d%d",&l,&r,&e);
                for(int i = 1;i <= k; i++){
//添加
                    add(tree[i],1,n,l,r,i*e);
                }
                for(int i = 1;i < k; i++){
                    while(query(tree[i],1,n,1,n) >= need[i]){ //查看当前树种是否有英雄需要升级
                        ll xl = query(tree[i],1,n,1,n);
                        int kk = i;
                        while(need[kk] <= xl && kk < k) kk++; //找到升级到第几级
                        int u = find(tree[i],1,n,xl);
                        sett(tree[kk],1,n,u,xl);   //设置新等级树上的 经验值
                        sett(tree[i],1,n,u,inf);  //原等级树经验值设置为负无穷
                    }
                }
            }
            else {
                scanf("%d%d",&l,&r);
                ll ans = 0;
                for(int i =1; i <= k; i++)
                    ans = max(ans,query(tree[i],1,n,l,r));
                printf("%I64d\n",ans);
            }
            ll tm = 0;
        }
        printf("\n");
    }
    return 0;
}










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GDRetop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值