码迷,mamicode.com
首页 > 其他好文 > 详细

hdu(3016) Man Down(线段树查询更新+dp)

时间:2015-07-05 16:50:28      阅读:151      评论:0      收藏:0      [点我收藏+]

标签:acm   线段树   

这道题目可以说是游戏的简化版。

题目的大致意思是:

首先我们只有两种板,一种使能量增加,另一种却使能量减少。

最开始人物站在最高层,然后它一开始有100的生命值,它每次下落只能掉到离他最近的木板上去,当然他只能从左端点或者是右端点往下掉。

但是如果没有板满足如下情况的话,那么他就掉到最底下去了,如果此时他的能量小于等于0的话,那么他就会死亡,那么则输出-1;否则输出他所能获得能量的最大值。

现在的任务是叫你输出最大所能获得最大能量值。

思路:

1)我们要找到当前区间的分别从左右端点下去离他最近的下面那个区间

在这里可以用线段树进行维护,但是这东西还是很巧妙啊,真是难想。。。

我们这里找到的某个板的左右端点的a[i].left或是a[i].right是指它下落会落到的那块板的标号。

线段树中query操作这里其实与染色操作相类似的,就是查找到已经被染色的区间的标号。

update操作其实就是对从l,r区间进行染色,染为第i的颜色。

2)找到所能获得的最大能量值,这里要dp来做,虽然我没有想到这道题竟然可以这样转化方程:

dp方程:dp[left]=max(dp[left],dp[i]+a[a[i].left].val) ,  dp[left]等于要不是不经过第i块木板而下来的,要不是经过第i块木板下来的,这样的话就要加上第i块木板所含有的价值,显然,dp方程就是在这两个方案中寻找最大的价值。

参考来源:http://xuyemin520.is-programmer.com/posts/25907.html

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
#include<map>
using namespace std;
#define maxn 111111
int dp[maxn];
struct node{
	int l,r;
	int color;
}tree[maxn*4];
struct hh{
	int xl,xr;
	int h,val;
	int left,right;
}a[maxn];
bool cmp(hh a,hh b){
	return a.h<b.h;
}
void pushdown(int v){
	int temp=v<<1;
	tree[temp].color=tree[v].color;
	tree[temp+1].color=tree[v].color;
	tree[v].color=-1;
}
void build(int l,int r,int v){
	tree[v].l=l;
	tree[v].r=r;
	tree[v].color=0;
	if(l==r) return ;
	int mid=(l+r)>>1;
	int temp=v<<1;
	build(l,mid,temp);
	build(mid+1,r,temp+1);
}
void update(int l,int r,int v,int cnt){
	if(l<=tree[v].l&&tree[v].r<=r){
		tree[v].color=cnt;
		return; 
	}
	if(tree[v].color!=-1) pushdown(v);
	int temp=v<<1;
	int mid=(tree[v].l+tree[v].r)>>1;
	if(r<=mid) update(l,r,temp,cnt);
	else if(l>mid) update(l,r,temp+1,cnt);
	else{
		update(l,mid,temp,cnt);
		update(mid+1,r,temp+1,cnt);
	}
}
int query(int t,int v,int l,int r){
	if(tree[v].color!=-1){
		return tree[v].color;
	}
	int mid=(tree[v].l+tree[v].r)>>1;
	int temp=v<<1;
	if(t<=mid) query(t,temp,l,mid);
	else if(t>mid) query(t,temp+1,mid+1,r);
}
int main(){
	int n;
	while(~scanf("%d",&n)){
		memset(dp,0,sizeof(dp));
		int lmax=-1;
		for(int i=1;i<=n;i++){
			scanf("%d%d%d%d",&a[i].h,&a[i].xl,&a[i].xr,&a[i].val);
			if(lmax<a[i].xr) lmax=a[i].xr;
		}
		build(1,lmax,1);
		update(1,lmax,1,0);
		sort(a+1,a+1+n,cmp);
		for(int i=1;i<=n;i++){
			a[i].left=query(a[i].xl,1,1,lmax);
			a[i].right=query(a[i].xr,1,1,lmax);
			//printf("%d %d\n",a[i].left,a[i].right);
			update(a[i].xl,a[i].xr,1,i);          //!!!
		}
		dp[n]=100+a[n].val;
		for(int i=n;i>=1;i--){
			if(dp[i]>0){
				dp[a[i].left]=max(dp[a[i].left],dp[i]+a[a[i].left].val);
				dp[a[i].right]=max(dp[a[i].right],dp[i]+a[a[i].right].val);
			}
		}
		if(dp[0]<=0) printf("-1\n");
		else printf("%d\n",dp[0]);
	}
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

hdu(3016) Man Down(线段树查询更新+dp)

标签:acm   线段树   

原文地址:http://blog.csdn.net/acmer_hades/article/details/46763405

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!