HDU3954 Level up

HDU3954 Level up

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


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)
******************************************************************************
题目大意:有n个人打怪升级,每一波怪具有e的经验由编号为a到b的人打掉并获得经验,每个人获得的经验为这个人当前等级k*e的经验,当一个人的经验到答规定范围他就可以升级。然后有几次询问,问从a到b这些人中经验最高的人的经验是多少。
解体思路:线段树变种,可以说变种吗?大概是拓展应用吧,我觉得是把延时标记给拓展了一下。对于线段树每个节点,首先有固定的左端点和右端点,然后千变万化的就是延时标记。这道题的突破点在人的升级上。如果每次把经验都加到每个叶子,也就是每个人上,然后再返回,那么线段树就毫无意义了,我们希望的是,让经验加到一段区间里面,然后可以马上返回,这时候,我在每个节点定义了一个val数组,记录这颗子树下面,每个等级的人的最高经验,下次如果有经验加在这个区间里面,而这段区间里面的人加上这个经验都不会升级,那就可以暂时把经验存在这个节点而不用下传了,只有当经验加下去,人要升级了,才往下传,这个延时标记比较犀利。
详见代码:
//#pragma comment(linker,"/STACK:65536000")
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <iostream>
#include <queue>
#include <stack>
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#define N 10005
#define M
#define E
#define inf 0x3f3f3f3f
#define eps 1e-8
#define linf (LL)1<<60
#define dinf 1e20
#define LL long long
#define clr(a,b) memset(a,b,sizeof(a))
#define D(a) ((a)*(a))
using namespace std;

struct Lt
{
    int le,ri,val[12],flag,rst;
}lt[N*6];

int lim[12],n,k,q;

void build(int rt,int le,int ri)
{
    lt[rt].le=le;
    lt[rt].ri=ri;
    clr(lt[rt].val,-1);
    lt[rt].val[1]=0;
    lt[rt].flag=0;
    lt[rt].rst=0;
    if(le==ri)return ;
    int mid=(le+ri)>>1;
    build(rt<<1,le,mid);
    build(rt<<1|1,mid+1,ri);
}

void update(int rt,int le,int ri,int rst)
{
    if(lt[rt].le==lt[rt].ri)
    {
        lt[rt].flag=1;
        int id;
        for(id=1;id<=k;id++)if(~lt[rt].val[id])break;
        int v=(lt[rt].rst+rst)*id+lt[rt].val[id];
        lt[rt].val[id]=-1;
        for(id=1;id<k;id++)if(v<lim[id])break;
        lt[rt].val[id]=v;
        lt[rt].rst=0;
        return ;
    }
    if(lt[rt].le==le&&lt[rt].ri==ri)
    {
        int f=0;
        for(int i=1;i<k&&!f;i++)
            if(~lt[rt].val[i]&&lt[rt].val[i]+i*(lt[rt].rst+rst)>=lim[i])
                f=1;
        if(!f)
        {
            lt[rt].rst+=rst;
            lt[rt].flag=1;
            return ;
        }
    }
    if(lt[rt].flag)
    {
        update(rt<<1,lt[rt<<1].le,lt[rt<<1].ri,lt[rt].rst);
        update(rt<<1|1,lt[rt<<1|1].le,lt[rt<<1|1].ri,lt[rt].rst);
        lt[rt].flag=0;clr(lt[rt].val,-1);lt[rt].rst=0;
    }
    int mid=(lt[rt].le+lt[rt].ri)>>1;
    if(ri<=mid)update(rt<<1,le,ri,rst);
    else if(le>mid)update(rt<<1|1,le,ri,rst);
    else
    {
        update(rt<<1,le,mid,rst);
        update(rt<<1|1,mid+1,ri,rst);
    }
    for(int i=1;i<=k;i++)
    {
        if(~lt[rt<<1].val[i]&&~lt[rt<<1|1].val[i])
            lt[rt].val[i]=max(lt[rt<<1].val[i]+i*lt[rt<<1].rst,lt[rt<<1|1].val[i]+i*lt[rt<<1|1].rst);
        else if(~lt[rt<<1].val[i])lt[rt].val[i]=lt[rt<<1].val[i]+i*lt[rt<<1].rst;
        else if(~lt[rt<<1|1].val[i])lt[rt].val[i]=lt[rt<<1|1].val[i]+i*lt[rt<<1|1].rst;
        else lt[rt].val[i]=-1;
    }
}

int query(int rt,int le,int ri,int rst)
{
    if(lt[rt].le==le&&lt[rt].ri==ri)
    {
        for(int i=k;i>=1;i--)
            if(~lt[rt].val[i])
                return lt[rt].val[i]+lt[rt].rst*i+rst*i;
    }
    if(lt[rt].flag)rst+=lt[rt].rst;
    int mid=(lt[rt].le+lt[rt].ri)>>1;
    if(ri<=mid)return query(rt<<1,le,ri,rst);
    else if(le>mid)return query(rt<<1|1,le,ri,rst);
    else return max(query(rt<<1,le,mid,rst),query(rt<<1|1,mid+1,ri,rst));
}

int main()
{
    //freopen("/home/fatedayt/in","r",stdin);
    //freopen("/home/fatedayt/out1","w",stdout);
	int ncase;
	scanf("%d",&ncase);
	for(int h=1;h<=ncase;h++)
	{
	    scanf("%d%d%d",&n,&k,&q);
	    for(int i=1;i<k;i++)scanf("%d",&lim[i]);
	    build(1,1,n);
	    printf("Case %d:\n",h);
	    for(int i=1;i<=q;i++)
	    {
	        char d[3];
	        scanf("%s",d);
	        if(d[0]=='W')
	        {
	            int a,b,c;
	            scanf("%d%d%d",&a,&b,&c);
	            update(1,a,b,c);
	            a++;
	        }
	        else
	        {
	            int a,b;
	            scanf("%d%d",&a,&b);
	            printf("%d\n",query(1,a,b,0));
	        }
	    }
	    puts("");
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/Fatedayt/p/2450048.html