`算法题解` `LuoGU` P3128 [USACO15DEC]Max Flow P

题目链接

题解

点权的 树上差分

代码

#include <bits/stdc++.h>
//----
#define  LITERAL_  static constexpr
#define  GET_( _t, _i)  ::std::get< _i>( _t)
#define  PAR_( _type, _name)  const _type & _name
#define  IS_IN_RANGE_( _c, _l, _r)  ( ( (_c) >= (_l)) && ( (_c) <= (_r)))
#define  FOR_( _i, _l, _r, _s)  for( int _i = _l; _i <= _r; _i += _s)
#define  FOR_RE_( _i, _l, _r, _s)  for( int _i = _l; _i >= _r; _i -= _s)
//--
#ifdef  SUPIMO_DEBUG_
  #define DEBUG_( ...)  __Debug( __VA_ARGS__, __LINE__)
#else
  #define DEBUG_( ...)  ( void)0
#endif
//--
using namespace ::std;
using Ll_ = long long;
//--
bool __Debug_is_first = true;
template< class _Last>
void __Debug( _Last _last){
    if( __Debug_is_first){
        cout << "(Debug) ";
        __Debug_is_first = false;
    }
    cout << " [Line: " << _last << "]" << endl;
    __Debug_is_first = true;
}
template< class _Head, class ... _Other>
void __Debug( _Head _head, _Other ... _other ){
    if( __Debug_is_first){
        cout << "(Debug) ";
        __Debug_is_first = false;
    }
    cout << _head << ", ";
    __Debug( _other ...);
}
//----
LITERAL_ int N_ = int( 5e4) + 5;
LITERAL_ int Root_ = 1;
int N, M; //< (点数) (操作)
int Head[ N_], Ver[ N_ * 2], Nex[ N_ * 2], Edges;
int Log[ N_]; //< Log[ a] = b;  2^b <= a, 最大的b
int Depth[ N_], Fa[ N_][ 21];
int Diff[ N_]; //< 树上差分, 起点为叶节点, 即Diff[ i] = A[ i] - ( A[ son(i)]之和)
int A[ N_];
//--
void Init_graph(){
    Edges = 0;
    memset( Head, -1, sizeof( Head));
}
void Add_edge( PAR_( int, _a), PAR_( int , _b)){
    Ver[ Edges] = _b;
    Nex[ Edges] = Head[ _a];
    Head[ _a] = Edges;
    ++ Edges;
}
void Dfs_lca( PAR_( int, _cur), PAR_( int, _fa)){
    for( int nex, i = Head[ _cur]; ~i; i = Nex[ i]){
        nex = Ver[ i];
        if( nex != _fa){
            Depth[ nex] = Depth[ _cur] + 1;
            //--
            Fa[ nex][ 0] = _cur;
            FOR_( step, 1, Log[ Depth[ nex]], 1){
                Fa[ nex][ step] = Fa[ Fa[ nex][ step - 1]][ step - 1];
//                DEBUG_( nex, step, Fa[ nex][ step]);
            }
            //--
            Dfs_lca( nex, _cur);
        }
    }
}
void Build_lca(){
    { //* build `Log`
        FOR_( i, 1, N, 1){
            if( 1 == i){
                Log[ 1] = 0;
            }
            else{
                if( ( 1 << ( Log[ i - 1] + 1)) == i){
                    Log[ i] = Log[ i - 1] + 1;
                }
                else{
                    Log[ i] = Log[ i - 1];
                }
            }
        }
    }
    //--
    Depth[ Root_] = 0;
    Dfs_lca( Root_, -1);
}
int Lca( PAR_( int, _a), PAR_( int, _b)){
    int low = _a, hig = _b;
    if( Depth[ low] < Depth[ hig]){
        swap( low, hig);
    }
    while( Depth[ low] != Depth[ hig]){
        low = Fa[ low][ Log[ Depth[ low] - Depth[ hig]]];
    }
    if( low == hig){ //< 如果不判断, 假如low=Root, 则下面代码中的Log[ 0]是个未定义行为
        return low;
    }
    FOR_RE_( i, Log[ Depth[ low]], 0, 1){ //< not `Log[ low]`
        if( Fa[ low][ i] != Fa[ hig][ i]){
            low = Fa[ low][ i];
            hig = Fa[ hig][ i];
        }
    }
    assert( Fa[ low][ 0] == Fa[ hig][ 0]);
    return Fa[ low][ 0];
}
void Dfs_build_diff( PAR_( int, _cur), PAR_( int, _fa)){
    Diff[ _cur] = A[ _cur];
    for( int nex, i = Head[ _cur]; ~i; i = Nex[ i]){
        nex = Ver[ i];
        if( nex != _fa){
            Diff[ _cur] -= A[ nex];
            //--
            Dfs_build_diff( nex, _cur);
        }
    }
}
void Build_diff(){
//    memset( Diff, 0, sizeof( Diff)); //< 用这个也可以.
    Dfs_build_diff( Root_, -1);
}
void Dfs_restore_diff( PAR_( int, _cur), PAR_( int, _fa)){
    A[ _cur] = Diff[ _cur];
    for( int nex, i = Head[ _cur]; ~i; i = Nex[ i]){
        nex = Ver[ i];
        if( nex != _fa){
            Dfs_restore_diff( nex, _cur);
            A[ _cur] += A[ nex];
        }
    }
}
void Restore_diff(){
    Dfs_restore_diff( Root_, -1);
}
void __Solve(){
    Init_graph();
    scanf("%d%d", &N, &M);
    FOR_( i, 1, N-1, 1){
        int a, b;
        scanf("%d%d", &a, &b);
        Add_edge( a, b);
        Add_edge( b, a);
    }
    Build_lca();
    Build_diff();
    FOR_( i, 1, M, 1){
        int a, b;
        scanf("%d%d", &a, &b);
        int lca = Lca( a, b);
        int fa_lca = ( lca == Root_ ? -1 : Fa[ lca][ 0]);
        Diff[ a] += 1;
        Diff[ b] += 1;
        Diff[ lca] -= 1;
        if( fa_lca != -1){
            Diff[ fa_lca] -= 1;
        }
    }
    Restore_diff();
    int ans = 0;
    FOR_( i, 1, N, 1){
        ans = max( ans, A[ i]);
    }
    cout << ans  << endl;
}
//--
int main(){
    //--
    int tests = 1;
    // scanf("%d", &tests);
    for( int i = 0; i < tests; ++i){
        __Solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值