HDU 3016 Man Down(线段树区间单点查询+DP)
来源:互联网 发布:源站ip地址和域名 编辑:程序博客网 时间:2024/05/16 14:48
http://acm.hdu.edu.cn/showproblem.php?pid=3016
题意: 是男人就下100层。这个男人开始在最顶层,并且拥有100的能量,如果他能下到他下面的横木上,他将无条件获得横木的val。他只能从横木的左端点和右端点下落。要是中途他的能量小于或等于0,he will die~
解题思路:要求到达最后一层的能量最大值,显然要用DP。一开始自然而然能够想到将这些横木按照从大到小排序。然后,就要思考这个男人要怎样下落,因为他只能从左端点或者右端点下落,所以要找到离他当前横木最近的满足条件的横木下落。
这里要用到线段树,当横木按照从大到小的顺序排完序之后,将这些横木插入到线段树中,线段树中装入的值是:tr[i].l , tr[i].r,即这些横木的左端点和右端点, pushup的时候:
tr[i].l = min(tr[i<<1].l,tr[i<<1|1].l);
tr[i].r = max(tr[i<<1].r,tr[i<<1|1].r);
即非叶子节点存当前区间的左端点的最小值和右端点的最大值。具体为什么下面会用到。
然后按照横木从高到低模拟这个男人的运动。当男人位于第i块横木时,在线段树中查找(i+1,n)区间的满足能从左端点下降的最近的横木j,并且满足第i块横木的左端点大于第j块横木的左端点,第i块横木的左端点小于第j块横木的右端点。此时,非叶子节点存当前的左端点的最小值和右端点的最大值就有作用了。什么作用?优化啊,具体见代码;从右端点下降的过程同左端点。
如果能下降到第j块横木,那么dp[j] = max(dp[j],dp[i]+arr[j].val);
如果没有找到能符合条件的,那么 dp[n+1] = max(dp[n+1],dp[i])(我自己假设的第n+1块横木为地板,就相当于直接掉到地板上);
#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define LL long long#define lson l,mid,i<<1#define rson mid+1,r,i<<1|1#define clr(x,y) memset(x,y,sizeof(x))const int N =100000+10;struct Node{ int h,l,r,v; friend bool operator < (const Node a ,const Node b) { return a.h > b.h; }}arr[N];int dp[N];struct segment{ int l;//左端点的值 int r;//右端点的值}tr[N*4];void built (int l,int r,int i){ if(l==r) { tr[i].l = arr[l].l; tr[i].r = arr[l].r; return; } int mid=(l+r)>>1; built(lson); built(rson); tr[i].l = min(tr[i<<1].l,tr[i<<1|1].l);//pushup tr[i].r = max(tr[i<<1].r,tr[i<<1|1].r); return;}bool flag;int ans;void query(int l,int r,int i,int a,int b,int x,int op){ if(l>=a&&r<=b) { //如果此时的右端点的值小于该节点的l值,那么下面的节点也没有符合条件的点,直接return //如果此时的左端点的值大于该节点的l值,那么下面的节点也没有符合条件的点,直接return if(op==0 && tr[i].l<=arr[x].l) ; else if(op==1 && tr[i].r >=arr[x].r) ; else return; } if(l==r) { if(op==0 && tr[i].l<=arr[x].l && tr[i].r >=arr[x].l) flag=true,ans=l;//找到符合的点,return else if(op==1 && tr[i].r >=arr[x].r && tr[i].l<=arr[x].r) flag=true,ans=l; return; } int mid=(l+r)>>1; if(mid>=a) query(lson,a,b,x,op); if(flag) return; if(mid<b) query(rson,a,b,x,op); return;}int main(){ int n; while(~scanf("%d",&n)) { for(int i=1;i<=n;i++) scanf("%d%d%d%d",&arr[i].h,&arr[i].l,&arr[i].r,&arr[i].v); sort(arr+1,arr+1+n); built(1,n,1); clr(dp,0); dp[1]=arr[1].v+100; for(int i=1;i<n;i++) { if(dp[i]<=0) continue; //查找能从左端点下降的横木 ans=0,flag=false; query(1,n,1,i+1,n,i,0); if(ans) dp[ans] = max(dp[ans],dp[i]+arr[ans].v); else dp[n+1] = dp[i];//没有满足条件的,直接掉到地板上 //查找能从右端点下降的横木 ans=0,flag=false; query(1,n,1,i+1,n,i,1); if(ans) dp[ans] = max(dp[ans],dp[i]+arr[ans].v); else dp[n+1] = dp[i];//没有满足条件的,直接掉到地板上 } int res = max(dp[n+1],dp[n]); if(res>0) printf("%d\n",res); else printf("-1\n"); } return 0;}
- HDU 3016 Man Down(线段树区间单点查询+DP)
- Man Down(线段树+区间更新+单点查询+dp)
- hdu 3016 Man Down(线段树区间更新+dp)
- hdu(3016) Man Down(线段树查询更新+dp)
- hdu 3016 Man Down 线段树+dp
- hdu 3016 Man Down (线段树 + dp)
- 【HDU】3016 Man Down 线段树DP
- Hdu 3016 Man Down【线段树+Dp】
- HDU-3016:Man Down(线段树+DP)
- HDOJ3016Man Down(线段树(区间更新,单点查询)+DP)
- HDU 3016 Man Down (线段树+dp)
- hdu 3016 Man Down(简单线段树&简单DP)
- HDU 3016 Man Down(线段树 + DP)
- HDU 3016 Man Down(线段树+离散化+dp)
- hdu 3016 Man Down(成段更新,单点查询)
- hdu 3016 Man Down(线段树)
- hdu 3016 Man Down(线段树)
- HDU 3016 Man Down(线段树)
- 使用自定义聚集函数来实现分组合并字符串
- nginx学习笔记
- Android中ActivityManager(AM)的方法解释和几个使用场景介绍
- 设计模式学习之--单例模式
- cocos2d js 使用 cocos studio 生成的合图
- HDU 3016 Man Down(线段树区间单点查询+DP)
- Oracle和mysql的一些简单区别
- pem证书
- Tcp重传
- MFC WORD void*输出
- Android init进程分析——学习笔记
- cocos lua绑定感悟---tolua_isusertable及lua如何访问cocos静态函数的方法
- BZOJ 1692 [Usaco2007 Dec]队列变换 暴力(正解后缀数组)
- JProfiler入门笔记