hdu 3016 Man Down

题目大意:

就是一个游戏 叫做 是英雄就下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;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值