【題目鏈接】
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;
}
}