HDU--3954(线段树+特殊处理)

D - 1004
Time Limit:3000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

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) 
         
HH出的题,好经典的线段树。转一下大神的解释吧,好经典。

题意很简单,成段更新,成段询问,但是更新却和一般的线段树大不一样,每个点虽然接收到相同的信息,但是由于本身不同,最终得到的值也是不同的.用一般的延迟操作就搞不定了.

突破点在K,范围很小,只有10,可以考虑每次有人升级的时候,就递归的找下去,将这个人进行升级操作.由于找到某个人只需要logn的复杂度,每个人最多升k次,所以n个人的复杂度是O(nklogn)

用了两个辅助数组add[maxn]和MAX[maxk][maxn],add用于记录延迟标记,MAX[k]表示该区间等级为k的最大经验值.初始化add,MAX[1]为0,其他为-1,表示无人在这个等级.当MAX[k]的值大于等于Needk时,就对这个区间进行升级操作,和线段树操作一样递归的将这个区间能升级的人全部升级.

单次操作可能会是nlogn(每个人都升级),但是平均下来还是只有nklogn.

代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
#include<set>
#define INF 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
const int maxd=10000+5;

#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
typedef long long ll;
typedef pair<int,int> pii;
//---------------------------
int add[maxd<<2],_max[15][maxd<<2];
int need[15]= {0};
int n,k,op;

void pushup(int rt)
{
    for(int i=1; i<=k; ++i)
        _max[i][rt]=max(_max[i][rt<<1],_max[i][rt<<1|1]);
}

void pushdown(int rt)
{
    if(add[rt])
    {
        add[rt<<1]+=add[rt];
        add[rt<<1|1]+=add[rt];
        for(int i=1; i<=k; ++i)
        {
            if(_max[i][rt<<1]!=-1)///
                _max[i][rt<<1]+=add[rt]*i;
            if(_max[i][rt<<1|1]!=-1)
                _max[i][rt<<1|1]+=add[rt]*i;
        }
        add[rt]=0;
    }
}

void build(int l,int r,int rt)
{
    add[rt]=0;
    if(l==r)
    {
        _max[1][rt]=0;
        for(int i=2; i<=k; ++i)
            _max[i][rt]=-1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}

void levelup(int ki,int l,int r,int rt)
{
    if(l==r)
    {
        while(ki<k)
        {
            if(_max[ki][rt]>=need[ki])
            {
                _max[ki+1][rt]=_max[ki][rt];
                _max[ki][rt]=-1;
                ++ki;
            }
            else break;
        }
        return;
    }
    pushdown(rt);///??
    int m=(l+r)>>1;
    if(_max[ki][rt<<1] >=need[ki]) levelup(ki,lson);
    if(_max[ki][rt<<1|1]>=need[ki]) levelup(ki,rson);
    pushup(rt);

}

void update(int L,int R,int v,int l,int r,int rt)
{
    if(L<=l && r<=R)
    {
        add[rt]+=v;
        for(int i=k; i>=1; --i)
        {
            if(_max[i][rt]!=-1)
                _max[i][rt]+=v*i;
            if(i<k && _max[i][rt]>=need[i])
                levelup(i,l,r,rt);
        }
        return;
    }
    pushdown(rt);
    int m=(l+r)>>1;
    if(L<=m) update(L,R,v,lson);
    if(m<R) update(L,R,v,rson);
    pushup(rt);
}

int query(int L,int R,int l,int r,int rt)
{
    if(L<=l && r<=R)
    {
        for(int i=k; i>=1; --i)
            if(_max[i][rt]!=-1)
                return _max[i][rt];
    }
    pushdown(rt);
    int m=(l+r)>>1;
    int ret=0;
    if(L<=m) ret=max(ret,query(L,R,lson));
    if(m<R) ret=max(ret,query(L,R,rson));
    return ret;
}

int main()
{
    int kase;
    freopen("1.txt","r",stdin);
    scanf("%d",&kase);
    for(int cas=1; cas<=kase; ++cas)
    {
        printf("Case %d:\n",cas);
        scanf("%d%d%d",&n,&k,&op);
         build(1,n,1);
        for(int i=1; i<k; ++i)
            scanf("%d",&need[i]);

        while(op--)
        {
            char ch[2];
            int l,r,val;
            scanf("%s%d%d",ch,&l,&r);
          //  cout<<ch<<l<<r<<endl;
            if(ch[0]=='W')
            {
                scanf("%d",&val);
                // cout<<l<<r<<val<<n<<k<<op<<endl;
                update(l,r,val,1,n,1);
            }
            else
            {
                printf("%d\n",query(l,r,1,n,1));
            }
        }
        printf("\n");
    }
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值