BZOJ-3242: [Noi2013]快餐店(线段树)

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=3242

考虑如果图是一棵树的情况,那么理所当然选址是直径的中间,如果是环套树,那么由于最短路组成一棵树,所以是删去环上一条边组成的所有树的直径的最小值的一半,那么我们把环找出来,从中间一出断开,就可以用线段树求出直径在环上的情况,不在环上的情况分开处理即可。

代码:

#include <cstdio>

#include <algorithm>

#include <cstring>

 

using namespace std ;

 

#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 , l , r ) for ( int i = l ; i <= r ; ++ i )

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

 

typedef long long ll ;

 

const int maxn = 101000 , maxm = 201000 , inf = 0x7fffffff ;

const ll INF = ll( inf ) * ll( inf ) ;

 

struct edge {

    edge *next ;

    int t , d ;

} E[ maxm ] ;

 

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

 

inline void Init_edge(  ) {

    memset( head , 0 , sizeof( head ) ) ;

}

 

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

    pt -> t = t , pt -> next = head[ s ] , pt -> d = d ;

    head[ s ] = pt ++ ;

}

 

inline void addedge( int s , int t , int d ) {

    add( s , t , d ) , add( t , s , d ) ;

}

 

int n , sta[ maxn ] , tp = 0 , pos[ maxn ] ;

int ve[ maxn ] , vn = 0 , dn[ maxn ] , nxt[ maxn ] , lst[ maxn ] ;

bool ud[ maxn ] , fg[ maxn ] ;

 

void getC( int now , int fa ) {

    sta[ pos[ now ] = ++ tp ] = now , ud[ now ] = true ;

    travel( now ) if ( p -> t != fa ) {

        if ( vn ) return ;

        dn[ now ] = p -> d ;

        if ( ! ud[ p -> t ] ) {

            getC( p -> t , now ) ;

        } else {

            REP( i , pos[ p -> t ] , tp ) {

                nxt[ vn ] = dn[ ve[ vn ] = sta[ i ] ] ;

                vn ++ ;

            }

            Rep( i , vn ) lst[ i ] = nxt[ ( i - 1 + vn ) % vn ] , fg[ ve[ i ] ] = true ;

        }

    }

    ud[ now ] = false , tp -- ;

}

 

inline void upd( ll &x , ll &y , ll a ) {

    if ( a > x ) {

        y = x ;

        x = a ;

    } else if ( a > y ) y = a ;

}

 

inline void upd0( int &v , ll &d , int _v , ll _d ) {

    if ( _d > d ) {

        d = _d , v = _v ;

    }

}

 

inline void upd1( ll &x , ll y ) {

    if ( y > x ) x = y ;

}

 

ll dep[ maxn ][ 2 ] , dpth[ maxn ] , mh , dist[ maxn ] , ans ;

int mv ;

 

void geth( int now , int fa ) {

    upd0( mv , mh , now , dpth[ now ] ) ;

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

        dpth[ p -> t ] = dpth[ now ] + ll( p -> d ) ;

        geth( p -> t , now ) ;

    }

}

 

ll ans0 = 0 ;

 

inline void upd2( ll &mx , ll &mx0 , ll &mx1 , ll _mx , ll _mx0 , ll _mx1 ) {

    mx = max( max( mx , _mx ) , mx0 + _mx1 ) ;

    mx0 = max( mx0 , _mx0 ) , mx1 = max( mx1 , _mx1 ) ;

}

 

struct node {

 

    node *lc , *rc ;

    int l , r , mid ;

    ll mx , mx0 , mx1 , tag ;

 

    inline void pushdown(  ) {

        if ( tag ) {

            mx0 += tag , mx1 -= tag ;

            if ( l < r ) {

                lc -> tag += tag , rc -> tag += tag ;

            }

            tag = 0 ;

        }

    }

 

    inline void update(  ) {

        pushdown(  ) ;

        if ( l < r ) {

            lc -> pushdown(  ) , rc -> pushdown(  ) ;

            upd2( mx = lc -> mx , mx0 = lc -> mx0 , mx1 = lc -> mx1 , rc -> mx , rc -> mx0 , rc -> mx1 ) ;

        }

    }

 

} sgt[ maxn << 1 ] ;

 

typedef node* np ;

 

np ptt = sgt , root ;

 

void build( int l , int r , np &t ) {

    t = ptt ++ ;

    t -> l = l , t -> r = r ;

    if ( l == r ) {

        t -> mx = 0 , t -> mx0 = dep[ l ][ 0 ] - dist[ l ] , t -> mx1 = dep[ l ][ 0 ] + dist[ l ] , t -> tag = 0 ;

        return ;

    }

    t -> mid = ( l + r ) >> 1 ;

    build( l , t -> mid , t -> lc ) , build( t -> mid + 1 , r , t -> rc ) ;

    t -> update(  ) ;

}

 

void dec( int l , int r , ll d , np t ) {

    t -> pushdown(  ) ;

    if ( t -> l == l && r == t -> r ) {

        t -> tag += d ; return ;

    }

    if ( r <= t -> mid ) dec( l , r , d , t -> lc ) ; else

        if ( l > t -> mid ) dec( l , r , d , t -> rc ) ; else

            dec( l , t -> mid , d , t -> lc ) , dec( t -> mid + 1 , r , d , t -> rc ) ;

    t -> update(  ) ;

}

 

void change( int pos , ll mx0 , ll mx1 , np t ) {

    t -> pushdown(  ) ;

    if ( t -> l == t -> r ) {

        t -> mx = 0 , t -> mx0 = mx0 , t -> mx1 = mx1 ; return ;

    }

    change( pos , mx0 , mx1 , pos <= t -> mid ? t -> lc : t -> rc ) ;

    t -> update(  ) ;

}

 

void query( int l , int r , ll &mx , ll &mx0 , ll &mx1 , np t ) {

    if ( l > r ) {

        mx = mx0 = mx1 = 0 ; return ;

    }

    t -> pushdown(  ) ;

    if ( l == t -> l && r == t -> r ) {

        mx = t -> mx , mx0 = t -> mx0 , mx1 = t -> mx1 ;

        return ;

    }

    if ( r <= t -> mid ) query( l , r , mx , mx0 , mx1 , t -> lc  ) ; else

        if ( l > t -> mid ) query( l , r , mx , mx0 , mx1 , t -> rc ) ; else {

            query( l , t -> mid , mx , mx0 , mx1 , t -> lc ) ;

            ll a , b , c ; query( t -> mid + 1 , r , a , b , c , t -> rc ) ;

            upd2( mx , mx0 , mx1 , a , b , c ) ;

        }

}

 

int main(  ) {

    Init_edge(  ) ;

    scanf( "%d" , &n ) ;

    rep( i , n ) {

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

    }

    memset( pos , 0 , sizeof( pos ) ) , memset( ud , false , sizeof( ud ) ) , memset( fg , false , sizeof( fg ) ) ;

    getC( 1 , 0 ) ;

    Rep( i , vn ) {

        dep[ i ][ 0 ] = dep[ i ][ 1 ] = 0 ;

        int now = ve[ i ] ;

        travel( now ) if ( ! fg[ p -> t ] ) {

            dpth[ p -> t ] = mh = ll( p -> d ) ;

            geth( p -> t , now ) ;

            upd( dep[ i ][ 0 ] , dep[ i ][ 1 ] , mh ) ;

            dpth[ mv ] = mh = 0 ;

            geth( mv , 0 ) ;

            upd1( ans , mh ) ;

        }

        upd1( ans , dep[ i ][ 0 ] + dep[ i ][ 1 ] ) ;

    }

    ll temp = INF , a , b , c , x , y , z , sum = 0 ;

    dist[ 0 ] = 0 ;

    REP( i , 1 , ( vn - 1 ) ) dist[ i ] = dist[ i - 1 ] + ll( nxt[ i - 1 ] ) ;

    Rep( i , vn ) sum += nxt[ i ] ;

    build( 0 , vn - 1 , root ) ;

    Rep( i , vn ) {

        query( i , vn - 1 , a , b , c , root ) ;

        if ( i ) {

            query( 0 , i - 1 , x , y , z , root ) ;

            upd2( a , b , c , x , y , z ) ;

        }

        if ( a < temp ) temp = a ;

        dec( 0 , vn - 1 , nxt[ i ] , root ) ;

        ll d = sum - nxt[ i ] ;

        change( i , dep[ i ][ 0 ] - d , dep[ i ][ 0 ] + d , root ) ;

    }

    ans = max( ans , temp ) ;

    printf( "%.1f\n" , double( ans ) / 2.0 ) ;

    return 0 ;

}
    原文作者:AmadeusChan
    原文地址: https://www.jianshu.com/p/17f0531378e5
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞