题目大意:
就是一个游戏 叫做 是英雄就下100层。 如果中间人物的血量低于0 就算死亡,输出-1。要求输出人物到达最底层的时候的最大血量。
基本思路:
因为每一块木板只可能从左端或者右端跳下,并且跳下只可能被一块在他以下的木板接住,或者掉到地上。所以我们可以用动态规划的思想求解该问题。其中,dp[i] 表示 当我在第i块木板的时候获得的最大血量(暂时未包括木板带来的伤害或者血量增加效果)。当dp[i]+木板带来的效果<=0的时候,不在该木板上往左或者往右走。
由于木板的数目很多。所以,我们用线段树进行优化预处理出d[i][0]和d[i][1]。两者分别表示第i块木板从左端和从右端往下掉落到哪块木板。
所以,用线段树进行优化相当于:线段树的单点查询,成段更新的操作。具体代码见下:特别的,如果没有第一句的手动扩栈,c++会提示runtime error 栈溢出。
#pragma comment(linker, "/STACK:102400000,102400000");//手动扩栈,防止出现栈溢出的错误
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 400009
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int col[MAXN];//线段树延时标记
void downdate(int rt)
{
if(col[rt]!=-1)
{
col[rt<<1]=col[rt<<1|1]=col[rt];
col[rt]=-1;
}
return ;
}
void build(int l,int r,int rt)
{
col[rt]=-1;
if(l==r)
{
return ;
}
int m=(l+r)>>1;
build(lson);
build(rson);
}
void update(int l,int r,int rt,int ql,int qr,int num)//成段更新
{
if(l>=ql&&r<=qr)
{
col[rt]=num;
return ;
} downdate(rt);
int m=(l+r)>>1;
if(m>=ql)update(lson,ql,qr,num);
if(m<qr)update(rson,ql,qr,num);
}
int query(int l,int r,int rt,int p)//单点查询
{
if(col[rt]!=-1)return col[rt];
if(l==r)return 0;
int m=(l+r)>>1;
if(m<p)return query(rson,p);
else return query(lson,p);
}
struct node
{
int wl,wr,wv,wh;
} nod[100009];
bool cmp(node a,node b)
{
return a.wh<b.wh;
}
int main()
{
int n,m,i,j,x,y;
int d[100009][2];
while(scanf("%d",&n)!=-1)
{
build(1,100000,1);
for(i=0; i<n; i++)
scanf("%d%d%d%d",&nod[i].wh,&nod[i].wl,&nod[i].wr,&nod[i].wv);
sort(nod,nod+n,cmp);//在计算d的时候,需要把木板从下往上进行计算更新线段树
for(i=0; i<n; i++)
{
d[i+1][0]=query(1,100000,1,nod[i].wl);
d[i+1][1]=query(1,100000,1,nod[i].wr);
update(1,100000,1,nod[i].wl,nod[i].wr,i+1);
}
int dp[100009];
int ans[100009];
for(i=0;i<n;i++)
dp[i]=-111111;
dp[n]=100;
for(i=n; i>=1; i--)
{
ans[i]=dp[i]+nod[i-1].wv;
if(ans[i]<=0)continue;
int xl=d[i][0];//从第i块木板的左端掉落到达的木板编号
int xr=d[i][1];//从第i块木板的右端掉落到达的木板编号
dp[xl]=max(dp[xl],ans[i]);
dp[xr]=max(dp[xr],ans[i]);
}
ans[0]=dp[0];
if(ans[0]<=0)printf("-1\n");
else printf("%d\n",dp[0]);
}
return 0;
}