题意:给你n个板子,初始100生命,到达每个板子加血或者扣血,求从最上面的板子落到地面的最优解
题解:对于每一个木板,只有从左下或者从右下,所以从下往上来看,到达第n个木板的最优解为 dp[n] = max(dp[l],dp[r]) + value[n]
l 和 r 为n的左右端点下方的木板序号,然后,维护一个线段树,当一个木板计算完毕后,维护木板左端点到木板右端点的叶子节点的值为木板的序号(把下方的木板或者地板都盖住了!!)
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
#define maxn 100010
int tree[maxn<<2];
int dp[maxn];struct Node
{int l,r,h,val;
}node[maxn];bool cmp(Node a,Node b)
{return a.h < b.h;
}void PushUp(int rt)
{;
}void Build(int l,int r,int rt)
{
// cout<<l<<" "<<r<<endl;tree[rt] = 0;if( r == l ){return ;}int m = (r+l)>>1;Build(l,m,rt<<1);Build(m+1,r,rt<<1|1);PushUp(rt);
}void PushDown(int rt)
{if(tree[rt]){tree[rt<<1] = tree[rt];tree[rt<<1|1] = tree[rt];}tree[rt] = 0;
}void Update(int L,int R,int c,int l,int r,int rt)
{if( l >= L && r <= R ){tree[rt] = c;return ;}int m = (r+l)>>1;PushDown(rt);if(L<=m) Update(L,R,c,l,m,rt<<1);if(R>m) Update(L,R,c,m+1,r,rt<<1|1);PushUp(rt);
}int Query(int L,int l,int r,int rt)
{if( l == L && r == L){return tree[rt];}int m = (r+l)>>1;PushDown(rt);if(L<=m) return Query(L,l,m,rt<<1);if(L> m) return Query(L,m+1,r,rt<<1|1);
}int main()
{int n;
// freopen("in.txt","r",stdin);while(scanf("%d",&n)!=EOF){Build(1,maxn,1);CLR(dp,0);for(int i=1;i<=n;i++)scanf("%d%d%d%d",&node[i].h,&node[i].l,&node[i].r,&node[i].val);sort(node+1,node+1+n,cmp);for(int i=1;i<=n;i++){int l = Query(node[i].l,1,maxn,1);int r = Query(node[i].r,1,maxn,1);dp[i] = max(dp[l],dp[r]) + node[i].val;Update(node[i].l,node[i].r,i,1,maxn,1);}dp[n]+=100;if(dp[n]<=0)printf("-1\n");elseprintf("%d\n",dp[n]);}return 0;
}