HDU-3594-Level up(线段树)

Level up

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

题意:

有N个英雄,每个英雄的初始等级为1,初始经验为0,有K个等级,QW个操作。接下来一行中有K-1个数值,代表升到等级2,等级3……所要达到的经验。接下来的QW行里,每行是一个操作,操作有两类,(1)"l r e",代表区间[l,r]里的每个英雄将得到e乘以他的等级的经验。(2)"l r",表示查询区间[l,r]里经验最大值。有一个特殊点,就是我不是一级一级升级的,而是可以直接升,例如一共5级,升到每级的经验是 1 2 3 4,那么当英雄获得  2 经验的时候就可以直接升到3级了,不是获得1经验升到2级,再获得2经验升到3级。

题解:

线段树还是太菜了啊,感觉理解不够深刻,还应该再去学一波,这个题目就是用线段树维护区间经验最大值,区间内升级需要的最少的经验值,当我当前增加的经验小于我当前升级需要的最少经验时,我就用lazy记录下来,因为反正也不会让他升级,那么我就先记录,等之后在pushdown操作时对子区间进行更新,然后再对于某此区间,它需要升级的最小经验小于当前给的经验时,那么这段区间内就存在能够升级的点,那么我递归下去到节点中进行升级操作(我之前一直怕会T),然后就递归到那个点然后对那个点进行更改,注意有可能当前的经验值可以让级数升好多级的情况,然后更改该点的最大经验值,该点的升级所需要的最少经验值,然后在之后的pushup操作时更新父节点

代码:

#include<bits/stdc++.h>
#define N 10005
#define INF 0x3f3f3f3f
#define lson node<<1
#define rson node<<1|1
using namespace std;
int t,n,k,q,tmp=0;
int w[30];
struct ljh
{
	int l,r,lazy,mx,nv,level;
	//左右区间端点,lazy标记,区间最大经验值,区间内点升级需要的最少经验,级数
}e[N<<2];
inline void pushup(int node)
{
	e[node].mx=max(e[lson].mx,e[rson].mx);
	e[node].nv=min(e[lson].nv,e[rson].nv);
	e[node].level=max(e[lson].level,e[rson].level);
}
inline void pushdown(int node)
{
	if(e[node].lazy)
	{
		e[lson].mx+=(e[lson].level*e[node].lazy);
		e[rson].mx+=(e[rson].level*e[node].lazy);
		e[lson].nv-=e[node].lazy;
		e[rson].nv-=e[node].lazy;
		e[lson].lazy+=e[node].lazy;
		e[rson].lazy+=e[node].lazy;
		e[node].lazy=0;
	}
}
void Build(int node,int l,int r)
{
	e[node].l=l;
	e[node].r=r;
	e[node].lazy=0;
	if(l==r)
	{
	e[node].mx=0;
	e[node].level=1;
	e[node].nv=ceil((w[e[node].level+1]-e[node].mx)/e[node].level);
		return;
	}
	int m=(l+r)>>1;
	Build(lson,l,m);
	Build(rson,m+1,r);
	pushup(node);
}

void Update(int node,int x,int y,int z)
{
	if(x<=e[node].l&&e[node].r<=y&&e[node].nv>z)//不能升级,正常更新,进行标记,等到能升级的时候再用
	{
		e[node].nv-=z;
		e[node].mx+=(e[node].level*z);
		e[node].lazy+=z;
		return;
	}
	if(x<=e[node].l&&e[node].r<=y&&e[node].l==e[node].r)//更新到子节点
	{
		e[node].mx+=(e[node].level*z);
		while(e[node].mx>=w[e[node].level+1])e[node].level++; //判断能升到几级,注意一下升多级的情况
		e[node].lazy=0;
		e[node].nv=ceil((w[e[node].level+1]-e[node].mx)/e[node].level);//更新升级最小值
		return;
	}
	pushdown(node);
	int m=(e[node].l+e[node].r)>>1;
	if(x<=m)Update(lson,x,y,z);
	if(y>m)Update(rson,x,y,z);
	pushup(node);
}
int Query(int node,int x,int y)
{
	int Max=0;
	if(x<=e[node].l&&e[node].r<=y)
	{
		return e[node].mx;
	}
	pushdown(node);
	int m=(e[node].l+e[node].r)>>1;
	if(x<=m)Max=max(Max,Query(lson,x,y));
	if(y>m)Max=max(Max,Query(rson,x,y));
	pushup(node);
	return Max;
}
int main()
{
#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
#endif
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d%d%d",&n,&k,&q);
		memset(w,0,sizeof(w));
		for(int i=2;i<=k;i++)scanf("%d",&w[i]);
		w[1]=0;
		w[k+1]=INF;//升到第k级后就不能再升了
		Build(1,1,n);
		printf("Case %d:\n",++tmp);
		while(q--)
		{
			char op;
			int x,y,z;
			cin>>op;
			if(op=='W')
			{
				scanf("%d%d%d",&x,&y,&z);
				Update(1,x,y,z);
			}
			else
			{
				scanf("%d%d",&x,&y);
				printf("%d\n",Query(1,x,y));
			}
		}
		printf("\n");
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值