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;}
0 0
原创粉丝点击