HDU 3016 線段樹單點更新+DP

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

}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章