BZOJ-1758: [Wc2010]重建計劃(點分治+二分)

題目:http://www.lydsy.com/JudgeOnline/problem.php?id=1758

分?jǐn)?shù)規(guī)劃問題蚯窥,經(jīng)典做法二分答案,然后由于是樹的路徑問題童谒,所以在點分治里面套一個二分单旁,然后對于求max{a[i]+b[j]}(L<=i+j<=R),轉(zhuǎn)化成( L-i <= j <= R-i )饥伊,那么就出現(xiàn)一個左右端點都單調(diào)的RMQ問題象浑,那就單調(diào)隊列蔫饰,然后由于樹分治每次遞歸調(diào)用的復(fù)雜度必須只與子樹的大小相關(guān),那么必須按照當(dāng)前分治的重心的子樹最大高度從小到大枚舉子樹愉豺,這樣才能保證總共的復(fù)雜度為O(n log n log MaxV)篓吁。

代碼:

#include <cstdio>

#include <algorithm>

#include <cstring>

#include <vector>

 

using namespace std ;

 

#define addedge( s , t , d ) add( s , t , d ) , add( t , s , d )

#define travel( x ) for ( edge *p = Head[ x ] ; p ; p = p -> next )

#define rep( i , x ) for ( int i = 0 ; i ++ < x ; )

#define REP( i , a , b ) for ( int i = a ; i <= b ; ++ i )

#define DOWN( i , b , a ) for ( int i = b ; i >= a ; -- i )

 

const int maxn = 101000 , inf = 100000000 ;

const double esp = 0.0001 ;

 

struct edge {

    int t , d ;

    edge *next ;

} E[ maxn << 1 ] ;

 

edge *pt = E , *Head[ maxn ] ;

 

void add( int s , int t , int d ) {

    edge *p = pt ++ ;

    p -> t = t , p -> d = d , p -> next = Head[ s ] ;

    Head[ s ] = p ;

}

 

double ans = 0 ;

bool used[ maxn ] ;

int n , L , R ;

 

int size[ maxn ] , maxw , h[ maxn ] , maxh[ maxn ] , MAXH , root ;

double dep[ maxn ] ;

vector < int > sub[ maxn ] , tub[ maxn ] ;

 

inline void Upd( int &pos , int val ) {

    if ( val > pos ) pos = val ;

}

 

inline void upd( double &pos , double val ) {

    if ( val > pos ) pos = val ;

}

 

void getsize( int now , int fa ) {

    size[ now ] = 1 ;

    travel( now ) if ( p -> t != fa && ! used[ p -> t ] ) {

        getsize( p -> t , now ) , Upd( maxw , p -> d ) ;

        size[ now ] += size[ p -> t ] ;

    }

}

 

int q[ maxn ][ 2 ] , head , tail ;

 

inline void getroot( int now ) {

    bool flag ;

    int ve , pre , si = size[ now ] >> 1 ;

    q[ tail = 1 ][ 0 ] = now , q[ 1 ][ 1 ] = 0 , head = 0 ;

    for ( ; head < tail ; ) {

        flag = true ;

        ve = q[ ++ head ][ 0 ] ; pre = q[ head ][ 1 ] ;

        if ( size[ now ] - size[ ve ] > si ) flag = false ;

        travel( ve ) if ( p -> t != pre && ! used[ p -> t ] ) {

            if ( size[ p -> t ] > si ) flag = false ;

            q[ ++ tail ][ 0 ] = p -> t ; q[ tail ][ 1 ] = ve ;

        }

        if ( flag ) {

            root = ve ; return ;

        }

    }

}

 

void geth( int now , int fa , int num ) {

    Upd( maxh[ num ] , h[ now ] ) , sub[ num ].push_back( now ) , Upd( MAXH , h[ now ] ) ;

    travel( now ) if ( p -> t != fa && ! used[ p -> t ] ) {

        h[ p -> t ] = h[ now ] + 1 , dep[ p -> t ] = dep[ now ] + p -> d ;

        geth( p -> t , now , num ) ;

    }

}

 

double dp[ maxn ] , fun[ maxn ] ;

int Q[ maxn ] ;

 

inline bool check( double mid ) {

    REP( i , 0 , MAXH ) dp[ i ] = - inf ; dp[ 0 ] = 0 ;

    double temp = - inf ;

    int v , u , left , right , ret ;

    REP( i , 0 , MAXH ) {

        DOWN( k , tub[ i ].size(  ) - 1 , 0 ) {

            v = tub[ i ][ k ] ;

            REP( j , 0 , maxh[ v ] ) fun[ j ] = - inf ;

            REP( j , 0 , ( sub[ v ].size(  ) - 1 ) ) {

                u = sub[ v ][ j ] ;

                upd( fun[ h[ u ] ] , dep[ u ] - double( h[ u ] ) * mid ) ;

            }

            head = 1 , tail = 0 ;

            left = max( L - maxh[ v ] , 0 ) , right = min( R - maxh[ v ] , maxh[ v ] ) ;

            REP( j , left , right ) {

                for ( ; head <= tail && dp[ Q[ tail ] ] <= dp[ j ] ; -- tail ) ;

                Q[ ++ tail ] = j ;

            }

            DOWN( j , maxh[ v ] , 0 ) {

                for ( ; head <= tail && Q[ head ] < L - j ; ++ head ) ;

                if ( head <= tail ) upd( temp , fun[ j ] + dp[ Q[ head ] ] ) ;

                if ( R - ( j - 1 ) <= maxh[ v ] ) {

                    for ( ; head <= tail && dp[ Q[ tail ] ] <= dp[ R - ( j - 1 ) ] ; -- tail ) ;

                    Q[ ++ tail ] = R - ( j - 1 ) ;

                }

            }

            REP( j , 0 , maxh[ v ] ) upd( dp[ j ] , fun[ j ] ) ;

            if ( temp >= 0 ) return true ;

        }

    }

    return false ;

}

 

void solve( int now ) {

    maxw = 0 ; getsize( now , 0 ) ; getroot( now ) ;

    h[ root ] = dep[ root ] = 0 , MAXH = 0 ;

    travel( root ) if ( ! used[ p -> t ] ) {

        h[ p -> t ] = 1 , dep[ p -> t ] = p -> d , maxh[ p -> t ] = 0 , sub[ p -> t ].clear(  ) ;

        geth( p -> t , root , p -> t ) ;

    }

    REP( i , 0 , MAXH ) tub[ i ].clear(  ) ;

    travel( root ) if ( ! used[ p -> t ] ) tub[ maxh[ p -> t ] ].push_back( p -> t ) ;

    double l = 0 , r = maxw , mid ;

    while ( r - l > esp ) {

        mid = ( l + r ) / 2.0 ;

        if ( check( mid ) ) l = mid ; else r = mid ;

    }

    upd( ans , l ) , used[ root ] = true ;

    travel( root ) if ( ! used[ p -> t ] ) {

        solve( p -> t ) ;

    }

}

 

int main(  ) {

    memset( Head , 0 , sizeof( Head ) ) ;

    scanf( "%d%d%d" , &n , &L , &R ) ;

    REP( i , 2 , n ) {

        int s , t , d ; scanf( "%d%d%d" , &s , &t , &d ) ; addedge( s , t , d ) ;

    }

    memset( used , false , sizeof( used ) ) ;

    solve( 1 ) ;

    printf( "%.3f\n" , ans ) ;

    return 0 ;

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蚪拦,隨后出現(xiàn)的幾起案子杖剪,更是在濱河造成了極大的恐慌,老刑警劉巖驰贷,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盛嘿,死亡現(xiàn)場離奇詭異,居然都是意外死亡括袒,警方通過查閱死者的電腦和手機(jī)次兆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锹锰,“玉大人芥炭,你說我怎么就攤上這事〕切耄” “怎么了蚤认?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵米苹,是天一觀的道長糕伐。 經(jīng)常有香客問我,道長蘸嘶,這世上最難降的妖魔是什么良瞧? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮训唱,結(jié)果婚禮上褥蚯,老公的妹妹穿的比我還像新娘。我一直安慰自己况增,他們只是感情好赞庶,可當(dāng)我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著澳骤,像睡著了一般歧强。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上为肮,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天摊册,我揣著相機(jī)與錄音,去河邊找鬼颊艳。 笑死茅特,一個胖子當(dāng)著我的面吹牛忘分,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播白修,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼妒峦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了兵睛?” 一聲冷哼從身側(cè)響起舟山,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎卤恳,沒想到半個月后累盗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡突琳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年若债,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拆融。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡蠢琳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出镜豹,到底是詐尸還是另有隱情傲须,我是刑警寧澤,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布趟脂,位于F島的核電站泰讽,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏昔期。R本人自食惡果不足惜已卸,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望硼一。 院中可真熱鬧累澡,春花似錦、人聲如沸般贼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽哼蛆。三九已至蕊梧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間人芽,已是汗流浹背望几。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留萤厅,地道東北人橄抹。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓靴迫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親楼誓。 傳聞我的和親對象是個殘疾皇子玉锌,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容

  • "use strict";function _classCallCheck(e,t){if(!(e instanc...
    久些閱讀 2,034評論 0 2
  • 一年級語文上冊生字表 生字表一(共400字) 啊(ā)愛(ài)安(ān)岸(àn)爸(bà)八(bā)巴(bā)...
    meychang閱讀 2,804評論 0 6
  • 對于 D 題的原題意,出題人和驗題人賽前都沒有發(fā)現(xiàn)標(biāo)算存在的問題疟羹,導(dǎo)致了許多選手的疑惑和時間的浪費主守,在此表示真誠的...
    _Carryon閱讀 259評論 0 0
  • package com.bwie.text;import java.util.List;import com.bw...
    丶小丑閱讀 347評論 0 1
  • I installed a Win-Ubuntu dual system long time ago, but r...
    等流心0316閱讀 272評論 0 0