hdu3016 线段树+简单DP

这篇博客主要介绍了如何理解并解决HDU3016题目,首先按照木板高度排序,接着利用线段树记录每个木板左右两侧可跳跃的id。然后自顶向下应用动态规划进行求解,过程中确保能量始终不少于1。

看题目都看了半天,各种小条件,看了网上的思路才算把题目理解清楚了,主要是先按高度排序,再用线段树从下到上记录每块木板左右两边能跳到的id。然后从上到下作DP。中途能量不能小于1.


ACcode:

#include<stdio.h>
#include<iostream>
#include<algorithm>
using std::sort;

const int nsize=111111;
const int INF=100000000;

int *p[nsize<<1];
int lid[nsize],rid[nsize];
int trid[nsize<<2];
int dp[nsize];

struct Plank
{
    int h,l,r,v;
}lk[nsize];

bool cmp1(int *a1,int *a2)
{
    return *a1<*a2;
}

bool cmp2(Plank a1,Plank a2)
{
    return a1.h<a2.h;
}

void build(int rt,int l,int r)
{
    trid[rt]=0;
    if (l==r) return ;
    int m=(l+r)>>1;
    build(rt<<1,l,m);
    build(rt<<1|1,m+1,r);
}

int query(int rt,int l,int r,int k)
{
    if (trid[rt]!=-1) return trid[rt];
    int m=(l+r)>>1;
    if (k<=m) return query(rt<<1,l,m,k);
    else return query(rt<<1|1,m+1,r,k);
}

void PushDown(int rt)
{
    if (trid[rt]!=-1)
    {
        trid[rt<<1]=trid[rt<<1|1]=trid[rt];
        trid[rt]=-1;
    }
}

void update(int rt,int l,int r,int L,int R,int id)
{
    if (L<=l&&r<=R)
    {
        trid[rt]=id;
        return ;
    }
    PushDown(rt);
    int m=(l+r)>>1;
    if (L<=m) update(rt<<1,l,m,L,R,id);
    if (R>m)  update(rt<<1|1,m+1,r,L,R,id);
}

int Max(int a1,int a2)
{
    return a1>a2?a1:a2;
}

int main()
{
    int n,i,m,cur;
    while (scanf("%d",&n)!=EOF)
    {
        for (i=1;i<=n;i++)
        {
            scanf("%d %d %d %d",&lk[i].h,&lk[i].l,&lk[i].r,&lk[i].v);
            dp[i-1]=-1;
            p[i]=&lk[i].l;
            p[n+i]=&lk[i].r;
        }
        sort(p+1,p+n*2+1,cmp1);
        cur=*p[1]; *p[1]=1;
        for (m=1,i=2;i<=n*2;i++)
        {
            if (*p[i]!=cur) m++,cur=*p[i];
            *p[i]=m;
        }
        sort(lk+1,lk+n+1,cmp2);
        build(1,1,m);
        for (i=1;i<=n;i++)
        {
            lid[i]=query(1,1,m,lk[i].l);
            rid[i]=query(1,1,m,lk[i].r);
            update(1,1,m,lk[i].l,lk[i].r,i);
        }
        dp[n]=100+lk[n].v;
        for (i=n;i>0;i--)
        {
            dp[lid[i]]=Max(dp[lid[i]],dp[i]+lk[lid[i]].v);
            dp[rid[i]]=Max(dp[rid[i]],dp[i]+lk[rid[i]].v);
            if (dp[lid[i]]<=0) dp[lid[i]]=-INF;
            if (dp[rid[i]]<=0) dp[rid[i]]=-INF;
        }
        printf("%d\n",dp[0]>0?dp[0]:-1);
    }
    return 0;
}


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值