hdu3016 Man Down(线段树+dp)

题目链接:点击这里

题目大意:
多组输入,每组输入给出 n n n 块木板,木板高度为 h h h 左右边界分别为 l , r l,r l,r 其还有一个属性为 v a l val val,玩家初始有 100 100 100 滴血,玩家只能从当前木板的左右边界竖直向下跳,每跳到一块木板上玩家血量就会变化 v a l val val (val可能小于0) ,求从最上面的木板跳到地面玩家的最大生命值

题目分析:
首先我们要知道如何确定能从当前木板跳到哪个木板上,这个我们可以让高度从小到大用线段树做一次染色,代码中的 n e a r [ i ] [ 0 ] , n e a r [ i ] [ 1 ] near[i][0],near[i][1] near[i][0],near[i][1] 分别代表从 i i i 号木板的左右两边可以跳到的木板标号
知道这个以后我们就可以从上到下做一次 d p dp dp
d p [ i ] dp[i] dp[i] 为在高度为 i i i 的板子上最大的生命值,则有如下转移方程:
d p [ n e a r [ i ] [ 0 ] ] = m a x ( d p [ n e a r [ i ] [ 0 ] ] , d p [ i ] + v a l [ n e a r [ i ] [ 0 ] ] ) dp[near[i][0]] = max(dp[near[i][0]],dp[i]+val[near[i][0]]) dp[near[i][0]]=max(dp[near[i][0]],dp[i]+val[near[i][0]])
d p [ n e a r [ i ] [ 1 ] ] = m a x ( d p [ n e a r [ i ] [ 1 ] ] , d p [ i ] + v a l [ n e a r [ i ] [ 1 ] ] ) dp[near[i][1]] = max(dp[near[i][1]],dp[i]+val[near[i][1]]) dp[near[i][1]]=max(dp[near[i][1]],dp[i]+val[near[i][1]])

具体细节见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#define ll long long
#define inf 0x3f3f3f3f
#define Inf 0x3f3f3f3f3f3f3f3f
using namespace std;
int read()
{
	int res = 0,flag = 1;
	char ch = getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch == '-') flag = -1;
		ch = getchar();
	}
	while(ch>='0' && ch<='9')
	{
		res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
		ch = getchar();
	}
	return res*flag;
}
const int maxn = 3e5+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
struct node{
	int l,r,h,val;
	bool operator<(const node b)const
	{
		return h < b.h;
	}
}nod[maxn];
struct sgt{
	int val,lazy;
}a[maxn<<2];
int n,m,dp[maxn],near[maxn][2];
void pushdown(int root)
{
	if(a[root].lazy)
	{
		int tmp = a[root].lazy;
		a[root].lazy = 0;
		a[root<<1].lazy = tmp;
		a[root<<1|1].lazy = tmp;
		a[root<<1].val = a[root<<1|1].val = tmp;
	}
}
void build(int root,int l,int r)
{
	if(l == r)
	{
		a[root].val = 0;
		a[root].lazy = 0;
		return ;
	}
	int mid = l+r>>1;
	build(root<<1,l,mid);
	build(root<<1|1,mid+1,r);
	a[root].val = a[root].lazy = 0;
}
void updat(int root,int l,int r,int ql,int qr,int val)
{
	if(l>qr || r<ql) return ;
	if(l>=ql && r<=qr) 
	{
		a[root].lazy = a[root].val = val;
		return ;
	}
	int mid = l+r>>1;
	pushdown(root);
	updat(root<<1,l,mid,ql,qr,val);
	updat(root<<1|1,mid+1,r,ql,qr,val);
}
ll query(int root,int l,int r,int pos)
{
	if(l == r) return a[root].val;
	int mid = l+r>>1;
	pushdown(root);
	if(pos <= mid) return query(root<<1,l,mid,pos);
	else return query(root<<1|1,mid+1,r,pos);
}
int main()
{
	while(~scanf("%lld",&n))
	{
		memset(dp,0,sizeof(dp));
		int maxx = 0;
		for(int i = 1;i <= n;i++)
		{
			nod[i].h = read();nod[i].l = read(),nod[i].r = read();nod[i].val = read();
			maxx = max(maxx,nod[i].r);
		}
		build(1,1,maxx);
		sort(nod+1,nod+n+1);
		for(int i = 1;i <= n;i++)
		{
			near[i][0] = query(1,1,maxx,nod[i].l);
			near[i][1] = query(1,1,maxx,nod[i].r);
			updat(1,1,maxx,nod[i].l,nod[i].r,i);
		}
		dp[n] = 100+nod[n].val;
		for(int i = n;i;i--)
		{
			if(dp[i] <= 0) continue;
			dp[near[i][0]] = max(dp[near[i][0]],dp[i]+nod[near[i][0]].val);
			dp[near[i][1]] = max(dp[near[i][1]],dp[i]+nod[near[i][1]].val);
		}
		if(dp[n] > 0) printf("%d\n",dp[0]);
		else puts("-1");
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值