【题目链接】
http://acm.hdu.edu.cn/showproblem.php?pid=3016
【解题报告】
这道题目把线段树和DP结合起来了,所以并没有思路。参考了一篇题解,觉得讲的非常好:
http://www.cnblogs.com/scau20110726/archive/2013/05/11/3073398.html
–Titanium
这道题目的关键在于更新。
不加分析的给出算法:
线段树每个节点维护一个cover值表示它所对应的区间被cover值记录的线段所覆盖。如果没有被线段覆盖,cover值为-1.
从低到高往线段树里添加线段,每条线段先记录下他能到达的左边的比他低的线段的编号,右边的比他低的线段的编号,然后把这条线段加入线段树。
算法的正确性显而易见。从x点往下跳,如果可以跳到木板上,一定是某条木板(li,ri)覆盖了x点,离x点最近的,一定是最高的线段,所以高层线段覆盖低层线段是必须的。
之后跑一个DFS即可。
DFS的过程我漏讨论了一边可以直接掉到地板,一边可以掉到别的木板上的情况,wa了好几次TAT。
【参考代码】
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define root 1,1,100000
using namespace std;
const int INF=1e9;
const int maxn=1e5+50;
int N,ans;
int cover[maxn*4],dp[maxn];
int Left[maxn],Right[maxn];
struct Type
{
int l,r,h,value;
bool operator <( const Type& a ) const
{
return h<a.h; //h is dictinct
}
};
Type line[maxn];
void build( int O, int L, int R )
{
if( L==R ) cover[O]=-1;
else
{
int mid=(L+R)/2;
build( O*2,L,mid );
build( O*2+1,mid+1,R );
cover[O]=-1;
}
}
void pushdown( int O )
{
if( cover[O]!=-1 )
{
cover[O*2]=cover[O*2+1]=cover[O];
cover[O]=-1;
}
}
void update( int O, int L, int R, int qL,int qR,int v )
{
if( qL<=L && R<=qR ) cover[O]=v;
else
{
pushdown( O );
int mid=(L+R)/2;
if( qL<=mid )update( O*2, L, mid, qL, qR, v );
if( qR>mid )update( O*2+1, mid+1, R, qL, qR, v );
}
}
int query( int O, int L, int R, int x )
{
if( L==R )return cover[O];
if( cover[O]!=-1 )
{
if( L<=x && x<=R ) return cover[O];
}
else
{
int mid=(L+R)/2;
if( x<=mid )return query( O*2,L,mid,x );
else return query( O*2+1,mid+1,R,x );
}
}
void DFS( int pos )
{
if( Left[pos]==-1 && Right[pos]==-1 ){ ans=max( ans,dp[pos] ); return; }
if( Left[pos]!=-1 )
{
dp[Left[pos]]=max( dp[Left[pos]], dp[pos]+ line[Left[pos]].value ) ;
if( dp[Left[pos]]>0 ) DFS( Left[pos] );
}
else { ans=max( ans,dp[pos] ); }
if( Right[pos]!=-1 )
{
dp[Right[pos]]=max( dp[Right[pos]], dp[pos]+line[Right[pos]].value);
if( dp[Right[pos]]>0 ) DFS( Right[pos] );
}
else { ans=max(ans,dp[pos]); }
}
int main()
{
while( ~scanf("%d",&N) )
{
build( root );
for( int i=1; i<=N; i++ )scanf( "%d%d%d%d",&line[i].h,&line[i].l,&line[i].r,&line[i].value );
sort( line+1,line+1+N );
for( int i=1; i<=N; i++ )
{
Left[i]=query( root,line[i].l );
Right[i]=query( root,line[i].r );
update( root, line[i].l, line[i].r, i );
}
for( int i=1; i<=N; i++ ) dp[i]=-1*INF;
dp[N]=100+line[N].value;
if( dp[N]<=0 ) { printf("-1\n"); continue; }
ans=-1*INF;
DFS( N );
if( ans<=0 )printf( "-1\n" );
else printf("%d\n",ans);
}
return 0;
}
}