#ifndef INCLUDE_MODE #define INCLUDE_MODE // #define REACTIVE // #define USE_GETLINE #endif #ifdef INCLUDE_MAIN inline void Solve() { CIN( int , K , N , M ); CIN_A( int , A , K ); CIN_A( int , B , N ); Map A_hind{}; FOR( k , 0 , K ){ A_hind[A[k]]++; } using path_type = tuple; gE.resize( N + 2 ); FOR_ITR( A_hind ){ gE[0].push_back( { itr->first , 0 , itr->second } ); } FOREQ( i , 1 , N ){ gE[i].push_back( { N + 1 , 0 , B[i-1] } ); } FOR( j , 0 , M ){ CIN( ll , uj , vj , wj ); gE[uj].push_back( { vj , wj , K } ); gE[vj].push_back( { uj , wj , K } ); } Graph graph{ N + 2 , Get( gE ) }; MinimalCostFlow mcf{ move( graph ) , 1LL , 1LL<<62 }; // AbstractMinimalCostFlow mcf{ move( graph ) , Ring( 1LL ) , 1LL<<62 }; auto [answer,flow] = mcf.GetFlow( 0 , N + 1 , K ); RETURN( answer ); } REPEAT_MAIN(1); #else // INCLUDE_MAIN #ifdef INCLUDE_SUB // グラフ用 template Map gF; template vector gA; template vector> gE; template typename V> inline auto Get( const V& a ) { return [&]( const int& i ){ return a[i]; }; } // 圧縮時は中身だけ削除する。 inline void Experiment() { } // 圧縮時は中身だけ削除する。 inline void SmallTest() { } #define INCLUDE_MAIN #include __FILE__ #else // INCLUDE_SUB #ifdef INCLUDE_LIBRARY /* C-x 3 C-x o C-x C-fによるファイル操作用 BFS: c:/Users/user/Documents/Programming/Mathematics/Geometry/Graph/BreadthFirstSearch/compress.txt CoordinateCompress: c:/Users/user/Documents/Programming/Mathematics/SetTheory/DirectProduct/CoordinateCompress/compress.txt DFSOnTree c:/Users/user/Documents/Programming/Mathematics/Geometry/Graph/DepthFirstSearch/Tree/a.hpp Divisor: c:/Users/user/Documents/Programming/Mathematics/Arithmetic/Prime/Divisor/compress.txt Polynomial c:/Users/user/Documents/Programming/Mathematics/Polynomial/compress.txt UnionFind c:/Users/user/Documents/Programming/Mathematics/Geometry/Graph/UnionFindForest/compress.txt */ // VVV 常設でないライブラリは以下に挿入する。 #ifndef decldecay_t #define decldecay_t( VAR ) decay_t #endif template class VirtualPointedSet { public: virtual const U& Point() const noexcept = 0; inline const U& Unit() const noexcept; inline const U& Zero() const noexcept; inline const U& One() const noexcept; inline const U& Infty() const noexcept; inline const U& size() const noexcept; }; template class PointedSet : virtual public VirtualPointedSet { private: U m_b_U; public: inline PointedSet( const U& b_u = U() ); inline const U& Point() const noexcept; }; template class VirtualNSet { public: virtual U Transfer( const U& u ) = 0; inline U Inverse( const U& u ); }; template class AbstractNSet : virtual public VirtualNSet { private: F_U m_f_U; public: inline AbstractNSet( F_U f_U ); inline U Transfer( const U& u ); }; template class VirtualMagma { public: virtual U Product( const U& u0 , const U& u1 ) = 0; inline U Sum( const U& u0 , const U& u1 ); }; template class AbstractMagma : virtual public VirtualMagma { private: M_U m_m_U; public: inline AbstractMagma( M_U m_U ); inline U Product( const U& u0 , const U& u1 ); }; template inline PointedSet::PointedSet( const U& b_U ) : m_b_U( b_U ) {} template inline const U& PointedSet::Point() const noexcept { return m_b_U; } template inline const U& VirtualPointedSet::Unit() const noexcept { return Point(); } template inline const U& VirtualPointedSet::Zero() const noexcept { return Point(); } template inline const U& VirtualPointedSet::One() const noexcept { return Point(); } template inline const U& VirtualPointedSet::Infty() const noexcept { return Point(); } template inline const U& VirtualPointedSet::size() const noexcept { return Point(); } template inline AbstractNSet::AbstractNSet( F_U f_U ) : m_f_U( move( f_U ) ) { static_assert( is_invocable_r_v ); } template inline U AbstractNSet::Transfer( const U& u ) { return m_f_U( u ); } template inline U VirtualNSet::Inverse( const U& u ) { return Transfer( u ); } template inline AbstractMagma::AbstractMagma( M_U m_U ) : m_m_U( move( m_U ) ) { static_assert( is_invocable_r_v ); } template inline U AbstractMagma::Product( const U& u0 , const U& u1 ) { return m_m_U( u0 , u1 ); } template inline U VirtualMagma::Sum( const U& u0 , const U& u1 ) { return Product( u0 , u1 ); } template class VirtualMonoid : virtual public VirtualMagma , virtual public VirtualPointedSet {}; template class AdditiveMonoid : virtual public VirtualMonoid , public PointedSet { public: inline U Product( const U& u0 , const U& u1 ); }; template class MultiplicativeMonoid : virtual public VirtualMonoid , public PointedSet { public: inline MultiplicativeMonoid( const U& e_U ); inline U Product( const U& u0 , const U& u1 ); }; template class AbstractMonoid : virtual public VirtualMonoid , public AbstractMagma , public PointedSet { public: inline AbstractMonoid( M_U m_U , const U& e_U ); inline U Product( const U& u0 , const U& u1 ); }; template inline MultiplicativeMonoid::MultiplicativeMonoid( const U& e_U ) : PointedSet( e_U ) {} template inline AbstractMonoid::AbstractMonoid( M_U m_U , const U& e_U ) : AbstractMagma( move( m_U ) ) , PointedSet( e_U ) {} template inline U AdditiveMonoid::Product( const U& u0 , const U& u1 ) { return u0 + u1; } template inline U MultiplicativeMonoid::Product( const U& u0 , const U& u1 ) { return u0 * u1; } template inline U AbstractMonoid::Product( const U& u0 , const U& u1 ) { return m_m_U( u0 , u1 ); } template class VirtualGroup : virtual public VirtualMonoid , virtual public VirtualPointedSet , virtual public VirtualNSet {}; template class AdditiveGroup : virtual public VirtualGroup , public AdditiveMonoid { public: inline U Transfer( const U& u ); }; template class AbstractGroup : virtual public VirtualGroup , public AbstractMonoid , public AbstractNSet { public: inline AbstractGroup( M_U m_U , const U& e_U , I_U i_U ); }; template inline AbstractGroup::AbstractGroup( M_U m_U , const U& e_U , I_U i_U ) : AbstractMonoid( move( m_U ) , e_U ) , AbstractNSet( move( i_U ) ) {} template inline U AdditiveGroup::Transfer( const U& u ) { return -u; } template class VirtualRing { private: GROUP m_R0; MONOID m_R1; protected: inline VirtualRing( GROUP R0 , MONOID R1 ); public: inline U Sum( const U& u0 , const U& u1 ); inline const U& Zero() const noexcept; inline U Inverse( const U& u ); inline U Product( const U& u0 , const U& u1 ); inline const U& One() const noexcept; inline GROUP& AdditiveGroup() noexcept; inline MONOID& MultiplicativeMonoid() noexcept; }; template class Ring : virtual public VirtualRing,MultiplicativeMonoid> { public: inline Ring( const U& one_U ); }; template class AbstractRing : virtual public VirtualRing,AbstractMonoid> { public: inline AbstractRing( A_U a_U , const U& z_U , I_U i_U , M_U m_U , const U& e_U ); }; template inline VirtualRing::VirtualRing( GROUP R0 , MONOID R1 ) : m_R0( move( R0 ) ) , m_R1( move( R1 ) ) {} template inline Ring::Ring( const U& one_U ) : VirtualRing,MultiplicativeMonoid>( AdditiveGroup() , MultiplicativeMonoid( one_U ) ) {} template inline AbstractRing::AbstractRing( A_U a_U , const U& z_U , I_U i_U , M_U m_U , const U& e_U ) : VirtualRing,AbstractMonoid>( AbstractGroup( move( a_U ) , z_U , move( i_U ) ) , AbstractMonoid( move( m_U ) , e_U ) ) {} template inline U VirtualRing::Sum( const U& u0 , const U& u1 ) { return m_R0.Sum( u0 , u1 ); } template inline const U& VirtualRing::Zero() const noexcept { return m_R0.Zero(); } template inline U VirtualRing::Inverse( const U& u ) { return m_R0.Inverse( u ); } template inline U VirtualRing::Product( const U& u0 , const U& u1 ) { return m_R1.Product( u0 , u1 ); } template inline const U& VirtualRing::One() const noexcept { return m_R1.One(); } template inline GROUP& VirtualRing::AdditiveGroup() noexcept { return m_R0; } template inline MONOID& VirtualRing::MultiplicativeMonoid() noexcept { return m_R1; } #ifndef RET_TYPE #define RET_TYPE template using ret_t = decltype( declval()( declval()... ) ); #endif #ifndef INNER_TYPE #define INNER_TYPE template using inner_t = typename T::type; #endif #ifndef decldecay_t #define decldecay_t( VAR ) decay_t #endif // Enumeration:N->R1-->TとEnumeration_inv:T->R2-->Nは互いに逆写像である仮想関数。 template class VirtualGraph : public PointedSet { private: E m_edge; public: inline VirtualGraph( const int& size , E edge ); virtual R1 Enumeration( const int& i ) = 0; virtual R2 Enumeration_inv( const T& t ) = 0; inline void Reset(); ret_t Edge( const T& t ); using type = T; }; template class Graph : virtual public VirtualGraph { public: inline Graph( const int& size , E edge ); inline const int& Enumeration( const int& i ); inline const int& Enumeration_inv( const int& t ); template inline Graph GetGraph( F edge ) const; }; template class EnumerationGraph : virtual public VirtualGraph,ret_t,E> { private: Enum_T m_enum_T; Enum_T_inv m_enum_T_inv; public: inline EnumerationGraph( const int& size , Enum_T enum_T , Enum_T_inv enum_T_inv , E edge ); inline ret_t Enumeration( const int& i ); inline ret_t Enumeration_inv( const T& t ); template inline EnumerationGraph GetGraph( F edge ) const; }; template EnumerationGraph( const int& size , Enum_T enum_T , Enum_T_inv enum_T_inv , E edge ) -> EnumerationGraph(declval()(0).back())),Enum_T,Enum_T_inv,E>; // 推論補助のためにE::operator()はデフォルト引数が必要。 template class MemorisationGraph : virtual public VirtualGraph { private: int m_length; vector m_memory; Map m_memory_inv; public: inline MemorisationGraph( const int& size , E edge ); // push_backする可能性のあるvectorなので参照にしないように注意 inline T Enumeration( const int& i ); inline const int& Enumeration_inv( const T& t ); inline void Reset(); template inline MemorisationGraph GetGraph( F edge ) const; }; template MemorisationGraph( const int& size , E edge ) -> MemorisationGraph(declval()().back())),E>; template inline VirtualGraph::VirtualGraph( const int& size , E edge ) : PointedSet( size ) , m_edge( move( edge ) ) { static_assert( is_constructible_v && is_constructible_v && is_invocable_v ); } template inline Graph::Graph( const int& size , E edge ) : VirtualGraph( size , move( edge ) ) {} template inline EnumerationGraph::EnumerationGraph( const int& size , Enum_T enum_T , Enum_T_inv enum_T_inv , E edge ) : VirtualGraph,ret_t,E>( size , move( edge ) ) , m_enum_T( move( enum_T ) ) , m_enum_T_inv( move( enum_T_inv ) ) {} template inline MemorisationGraph::MemorisationGraph( const int& size , E edge ) : VirtualGraph( size , move( edge ) ) , m_length() , m_memory() , m_memory_inv() {} template inline ret_t VirtualGraph::Edge( const T& t ) { return m_edge( t ); } template inline const int& Graph::Enumeration( const int& i ) { return i; } template inline ret_t EnumerationGraph::Enumeration( const int& i ) { return m_enum_T( i ); } template inline T MemorisationGraph::Enumeration( const int& i ) { assert( 0 <= i && i < m_length ); return m_memory[i]; } template inline const int& Graph::Enumeration_inv( const int& i ) { return i; } template inline ret_t EnumerationGraph::Enumeration_inv( const T& t ) { return m_enum_T_inv( t ); } template inline const int& MemorisationGraph::Enumeration_inv( const T& t ) { if( m_memory_inv.count( t ) == 0 ){ assert( m_length < this->size() ); m_memory.push_back( t ); return m_memory_inv[t] = m_length++; } return m_memory_inv[t]; } template void VirtualGraph::Reset() {} template inline void MemorisationGraph::Reset() { m_length = 0; m_memory.clear(); m_memory_inv.clear(); } template template inline Graph Graph::GetGraph( F edge ) const { return Graph( this->size() , move( edge ) ); } template template inline EnumerationGraph EnumerationGraph::GetGraph( F edge ) const { return EnumerationGraph( this->size() , m_enum_T , m_enum_T_inv , move( edge ) ); } template template inline MemorisationGraph MemorisationGraph::GetGraph( F edge ) const { return MemorisationGraph( this->size() , move( edge ) ); } #define BELLMAN_FORD_BODY( INITIALISE_PREV , SET_PREV ) \ const U& zero = m_M.Zero(); \ const U& infty = this->Infty(); \ assert( zero < infty ); \ const int& size = m_G.size(); \ auto&& i_start = m_G.Enumeration_inv( t_start ); \ assert( 0 <= i_start && i_start < size ); \ vector found( size ); \ vector weight( size , infty ); \ found[i_start] = true; \ weight[i_start] = 0; \ INITIALISE_PREV; \ \ for( int length = 0 ; length < size ; length++ ){ \ \ for( int i = 0 ; i < size ; i++ ){ \ \ if( found[i] ){ \ \ const U& weight_i = weight[i]; \ assert( weight_i != infty ); \ auto&& edge_i = m_G.Edge( m_G.Enumeration( i ) ); \ \ for( auto itr = edge_i.begin() , end = edge_i.end() ; itr != end ; itr++ ){ \ \ auto&& j = m_G.Enumeration_inv( itr->first ); \ const U& edge_ij = itr->second; \ U temp = m_M.Sum( weight_i , edge_ij ); \ U& weight_j = weight[j]; \ \ if( weight_j > temp ){ \ \ found[j] = true; \ weight_j = move( temp ); \ SET_PREV; \ \ } \ \ } \ \ } \ \ } \ \ } \ \ bool valid = true; \ \ for( int i = 0 ; i < size && valid ; i++ ){ \ \ if( found[i] ){ \ \ const U& weight_i = weight[i]; \ auto&& edge_i = m_G.Edge( m_G.Enumeration( i ) ); \ \ for( auto itr = edge_i.begin() , end = edge_i.end() ; itr != end ; itr++ ){ \ \ auto&& j = m_G.Enumeration_inv( itr->first ); \ const U& edge_ij = itr->second; \ U& weight_j = weight[j]; \ const U temp = m_M.Sum( weight_i , edge_ij ); \ \ if( weight_j > temp ){ \ \ valid = false; \ break; \ \ } \ \ } \ \ } \ \ } \ // GRAPHはグラフG=(V_G,E_G:T->(T \times U)^{< \omega})に相当する型。 // 入力の範囲内で要件 // (0) Mは全順序可換モノイド構造である。 // (1) inftyがE_Gの値の各成分の第2成分|V_G|個以下の和で表せるいかなる数よりも大きい。 // が成り立つ場合にのみサポート。 // 単一始点全終点最短経路探索/経路復元なしO(|V_G| |E_G|) // 単一始点全終点最短経路探索/経路復元ありO(|V_G| |E_G|) template class AbstractBellmanFord : public PointedSet { private: GRAPH m_G; MONOID m_M; public: inline AbstractBellmanFord( GRAPH G , MONOID M , const U& infty ); // 負の閉路が存在すればfalse、存在しなければtrueを第1成分に返す。 tuple> GetDistance( const inner_t& t_start ); tuple,vector>>> GetPath( const inner_t& t_start ); }; template class BellmanFord : public AbstractBellmanFord,ll> { public: inline BellmanFord( GRAPH G ); }; template inline AbstractBellmanFord::AbstractBellmanFord( GRAPH G , MONOID M , const U& infty ) : PointedSet( infty ) , m_G( move( G ) ) , m_M( move( M ) ) { static_assert( ! is_same_v ); } template inline BellmanFord::BellmanFord( GRAPH G ) : AbstractBellmanFord,ll>( move( G ) , AdditiveMonoid<>() , 4611686018427387904 ) {} template tuple> AbstractBellmanFord::GetDistance( const inner_t& t_start ) { BELLMAN_FORD_BODY( , ); m_G.Reset(); return { valid , move( weight ) }; } template tuple,vector>>> AbstractBellmanFord::GetPath( const inner_t& t_start ) { BELLMAN_FORD_BODY( vector prev( size ) , prev[j] = i ); vector>> path( valid ? size : 0 ); if( valid ){ for( int j = 0 ; j < size ; j++ ){ auto& path_j = path[j]; int i = j; while( i != i_start ){ path_j.push_front( m_G.Enumeration( i ) ); i = prev[i]; } path_j.push_front( t_start ); } } m_G.Reset(); return { valid , move( weight ) , move( path ) }; } #define DIJKSTRA_BODY( INITIALISE_PREV , CHECK_FINAL , SET_PREV ) \ const U& zero = m_M.Zero(); \ const U& infty = this->Infty(); \ assert( zero < infty ); \ const int& size = m_G.size(); \ auto&& i_start = m_G.Enumeration_inv( t_start ); \ assert( 0 <= i_start && i_start < size ); \ set> vertex{}; \ vector found( size ); \ vector weight( size , infty ); \ vertex.insert( pair( weight[i_start] = zero , i_start ) ); \ INITIALISE_PREV; \ \ while( ! vertex.empty() ){ \ \ auto begin = vertex.begin(); \ auto [weight_i,i] = *begin; \ CHECK_FINAL; \ found[i] = true; \ vertex.erase( begin ); \ auto&& edge_i = m_G.Edge( m_G.Enumeration( i ) ); \ list> changed_vertex{}; \ \ for( auto itr = edge_i.begin() , end = edge_i.end() ; itr != end ; itr++ ){ \ \ auto&& j = m_G.Enumeration_inv( itr->first ); \ \ if( !found[j] ){ \ \ const U& edge_ij = itr->second; \ U temp = m_M.Sum( weight_i , edge_ij ); \ assert( !( temp < edge_ij ) && temp < infty ); \ U& weight_j = weight[j]; \ \ if( weight_j > temp ){ \ \ if( weight_j != infty ){ \ \ vertex.erase( pair( weight_j , j ) ); \ \ } \ \ SET_PREV; \ changed_vertex.push_back( pair( weight_j = move( temp ) , j ) ); \ \ } \ \ } \ \ } \ \ for( auto itr_changed = changed_vertex.begin() , end_changed = changed_vertex.end() ; itr_changed != end_changed ; itr_changed++ ){ \ \ vertex.insert( *itr_changed ); \ \ } \ \ } \ // GRAPHはグラフG=(V_G,E_G:T->(T \times U)^{< \omega})に相当する型。 // 入力の範囲内で要件 // (0) Mは全順序可換モノイド構造である。 // (1) E_Gの値の各成分の第2成分がM.Zero()以上である。 // (2) inftyがE_Gの値の各成分の第2成分|V_G|個以下の和で表せるいかなる数よりも大きい。 // (3) Vの各要素u,vに対し、辺u->vが複数存在する場合は重みが最小のものが前にpushされている。 // が成り立つ場合にのみサポート。 // 単一始点単一終点最短経路探索/経路復元なしO((|V_G|+|E_G|)log |V_G|) // 単一始点単一終点最短経路探索/経路復元ありO((|V_G|+|E_G|)log |V_G|) // 単一始点全終点最短経路探索/経路復元なしO((|V_G|+|E_G|)log |V_G|) // 単一始点全終点最短経路探索/経路復元ありO(|V_G|^2 + |E_G| log |V_G|) // O((|V_G|+|E_G|)log |V_G|)が間に合わない場合は、 // 始点からの距離を格納して一番近い未訪問点を全探策で探し距離を更新するO(|V_G|^2)版を検討。 template class AbstractDijkstra : public PointedSet { private: GRAPH m_G; MONOID m_M; public: inline AbstractDijkstra( GRAPH G , MONOID M , const U& infty ); // 経路が存在しない場合の返り値はinfty U GetDistance( const inner_t& t_start , const inner_t& t_final ); vector GetDistance( const inner_t& t_start ); pair>> GetPath( const inner_t& t_start , const inner_t& t_final ); pair,vector>>> GetPath( const inner_t& t_start ); }; template class Dijkstra : public AbstractDijkstra,ll> { public: inline Dijkstra( GRAPH G ); }; template inline AbstractDijkstra::AbstractDijkstra( GRAPH G , MONOID M , const U& infty ) : PointedSet( infty ) , m_G( move( G ) ) , m_M( move( M ) ) { static_assert( ! is_same_v ); } template inline Dijkstra::Dijkstra( GRAPH G ) : AbstractDijkstra,ll>( G , AdditiveMonoid<>() , 4611686018427387904 ) {} template U AbstractDijkstra::GetDistance( const inner_t& t_start , const inner_t& t_final ) { auto&& i_final = m_G.Enumeration_inv( t_final ); DIJKSTRA_BODY( , if( i == i_final ){ break; } , ); U answer{ move( weight[i_final] ) }; m_G.Reset(); return answer; } template vector AbstractDijkstra::GetDistance( const inner_t& t_start ) { DIJKSTRA_BODY( , , ); m_G.Reset(); return weight; } template pair>> AbstractDijkstra::GetPath( const inner_t& t_start , const inner_t& t_final ) { auto&& i_final = m_G.Enumeration_inv( t_final ); DIJKSTRA_BODY( vector prev( size ) , if( i == i_final ){ break; } , prev[j] = i ); int i = i_final; list> path{}; while( i != i_start ){ path.push_front( m_G.Enumeration( i ) ); i = prev[i]; } path.push_front( t_start ); U answer{ move( weight[i_final] ) }; m_G.Reset(); return { move( answer ) , move( path ) }; } template pair,vector>>> AbstractDijkstra::GetPath( const inner_t& t_start ) { DIJKSTRA_BODY( vector prev( size ) , , prev[j] = i ); vector>> path( size ); for( int j = 0 ; j < size ; j++ ){ auto& path_j = path[j]; int i = j; while( i != i_start ){ path_j.push_front( m_G.Enumeration( i ) ); i = prev[i]; } path_j.push_front( t_start ); } m_G.Reset(); return { move( weight ) , move( path ) }; } #define POTENTIALISED_DIJKSTRA_BODY( DISTANCE , WEIGHT , ... ) \ const U& infty = this->Infty(); \ if( m_valid ){ \ \ const U& zero = m_M.Zero(); \ auto edge = [&]( const T& t ){ \ \ const U& potential_i = m_potential[m_G.Enumeration_inv( t )]; \ assert( potential_i < infty ); \ auto edge_i = m_G.Edge( t ); \ list> answer{}; \ \ for( auto itr = edge_i.begin() , end = edge_i.end() ; itr != end ; itr++ ){ \ \ auto& e = *itr; \ \ if( m_on( e ) ){ \ \ const auto& v_j = get<0>( e ); \ U& w_j = get<1>( e ); \ const U& potential_j = m_potential[m_G.Enumeration_inv( v_j )]; \ assert( w_j < infty && potential_j < infty ); \ const U potential_j_inv = m_M.Inverse( potential_j ); \ w_j = m_M.Sum( m_M.Sum( w_j , potential_i ) , potential_j_inv ); \ assert( !( w_j < zero ) && w_j < infty ); \ answer.push_back( { v_j , move( w_j ) } ); \ \ } \ \ } \ \ return answer; \ \ }; \ \ auto G = m_G.GetGraph( move( edge ) ); \ AbstractDijkstra d{ move( G ) , m_M , infty }; \ auto value = d.Get ## DISTANCE( m_t_start ); \ const int& size = m_G.size(); \ \ for( int i = 0 ; i < size ; i++ ){ \ \ auto& weight_i = WEIGHT[i]; \ \ if( weight_i != infty ){ \ \ weight_i = m_M.Sum( weight_i , m_potential[i] ); \ \ } \ \ } \ \ return { m_valid , __VA_ARGS__ }; \ \ } \ \ auto edge = [&]( const T& t ){ \ \ auto&& edge_i = m_G.Edge( t ); \ list> answer{}; \ \ for( auto itr = edge_i.begin() , end = edge_i.end() ; itr != end ; itr++ ){ \ \ if( m_on( *itr ) ){ \ \ answer.push_back( { get<0>( *itr ) , get<1>( *itr ) } ); \ \ } \ \ } \ \ return answer; \ \ }; \ \ auto G = m_G.GetGraph( move( edge ) ); \ AbstractBellmanFord d{ G , m_M , infty }; \ return d.Get ## DISTANCE( m_t_start ); \ // GRAPHはグラフG=(V_G,E_G:T->(T \times U)^{< \omega})に相当する型。 // Onは写像on:im(edge)->\{0,1\}に相当する型。 // 入力の範囲内で要件 // (0) Mは全順序アーベル群構造である。 // (1) inftyが「E_Gの値の各成分の第2成分と2点間ポテンシャル差の和」の|V_G|個以下の和で表せるいかなる数よりも大きい。 // (2) Vの各要素u,vに対し、辺u->vが複数存在する場合は重みが最小のものが前にpushされている。 // が成り立つ場合にのみサポート。 // 負辺を含む場合/含まない場合 // 構築O(|V_G| |E_G|)/O(|V_G|) // 単一始点全終点最短経路探索/経路復元なしO((|V_G|+|E_G|)log |V_G|) // 単一始点全終点最短経路探索/経路復元ありO(|V_G|^2 + |E_G| log |V_G|) template class AbstractPotentialisedDijkstra : public PointedSet { private: GRAPH m_G; GROUP m_M; T m_t_start; // 全ての辺を許容する場合に始点から負のループに到達可能か否か。 bool m_valid; // 全ての辺を許容する場合の始点からのコスト。 vector m_potential; // どの辺を許容するかを決める関数オブジェクト。 On m_on; public: inline AbstractPotentialisedDijkstra( GRAPH G , GROUP M , const T& t_start , const U& infty , On on , const bool& negative = true ); inline AbstractPotentialisedDijkstra( GRAPH G , GROUP M , const T& t_start , const U& infty , const bool& valid , vector potential , On on ); inline const bool& Valid() const noexcept; inline const vector& Potential() const noexcept; inline void SetPotential( const bool& valid , vector potential ); tuple> GetDistance(); tuple,vector>> GetPath(); }; template class PotentialisedDijkstra : public AbstractPotentialisedDijkstra,ll,On> { public: template inline PotentialisedDijkstra( GRAPH G , const T& t_start , Args&&... args ); }; template inline AbstractPotentialisedDijkstra::AbstractPotentialisedDijkstra( GRAPH G , GROUP M , const T& t_start , const U& infty , On on , const bool& negative ) : AbstractPotentialisedDijkstra( move( G ) , move( M ) , t_start , infty , true , vector() , move( on ) ) { if( negative ){ auto edge = [&]( const int& t ){ auto&& edge_i = m_G.Edge( t ); list> answer{}; for( auto itr = edge_i.begin() , end = edge_i.end() ; itr != end ; itr++ ){ const auto& e = *itr; answer.push_back( { get<0>( e ) , get<1>( e ) } ); } return answer; }; auto G = m_G.GetGraph( move( edge ) ); AbstractBellmanFord bf{ move( G ) , m_M , infty }; auto [valid,potential] = bf.GetDistance( m_t_start ); m_valid = valid; m_potential = move( potential ); } else { m_potential = vector( m_G.size() , m_M.Zero() ); } } template inline AbstractPotentialisedDijkstra::AbstractPotentialisedDijkstra( GRAPH G , GROUP M , const T& t_start , const U& infty , const bool& valid , vector potential , On on ) : PointedSet( infty ) , m_G( move( G ) ) , m_M( move( M ) ) , m_t_start( t_start ) , m_valid( valid ) , m_potential( potential ) , m_on( move( on ) ) { static_assert( is_invocable_r_v().Edge(declval()).back())> ); } template template inline PotentialisedDijkstra::PotentialisedDijkstra( GRAPH G , const T& t_start , Args&&... args ) : AbstractPotentialisedDijkstra,ll,On>( move( G ) , AdditiveGroup<>() , t_start , 4611686018427387904 , forward>( args )... ) {} template inline const bool& AbstractPotentialisedDijkstra::Valid() const noexcept { return m_valid; } template inline const vector& AbstractPotentialisedDijkstra::Potential() const noexcept { return m_potential; } template inline void AbstractPotentialisedDijkstra::SetPotential( const bool& valid , vector potential ) { assert( int( potential.size() ) == m_G.size() ); m_valid = valid; m_potential = move( potential ); } template tuple> AbstractPotentialisedDijkstra::GetDistance() { POTENTIALISED_DIJKSTRA_BODY( Distance , value , move( value ) ); } template tuple,vector>> AbstractPotentialisedDijkstra::GetPath() { POTENTIALISED_DIJKSTRA_BODY( Path , get<0>( value ) , move( get<0>( value ) ) , move( get<1>( value ) ) ); } // GRAPHはグラフG=(V_G,E_G:T->(T \times U(コスト) \times U(容量))^{< \omega})に相当する型。 // 入力の範囲内で要件 // (0) Rは全順序環構造である。 // (1) E_Gの値の各成分の第2成分がM.Zero()以上である。 // (2) inftyが「E_Gの値の各成分の第2成分と2点間ポテンシャル差の和」の|V_G|個以下の和のf倍で表せるいかなる数よりも大きい。 // (3) Vの各要素u,vに対し、辺u->vが複数存在しない。 // が成り立つ場合にのみサポート。 // 構築O(|V_G| + |E_G|) // 単一始点単一終点最小費用流路探索O(|V_G| |E_G| + F (|V_G|+|E_G|)log |V_G|) template class AbstractMinimalCostFlow : public PointedSet { private: GRAPH m_G; RING m_R; public: inline AbstractMinimalCostFlow( GRAPH G , RING R , const U& infty ); pair,U>>>> GetFlow( const inner_t& t_start , const inner_t& t_final , U f ); }; template class MinimalCostFlow : public AbstractMinimalCostFlow,U> { public: inline MinimalCostFlow( GRAPH G , const U& one_U , const U& infty ); }; template inline AbstractMinimalCostFlow::AbstractMinimalCostFlow( GRAPH G , RING R , const U& infty ) : PointedSet( infty ) , m_G( move( G ) ) , m_R( move( R ) ) {} template inline MinimalCostFlow::MinimalCostFlow( GRAPH G , const U& one_U , const U& infty ) : AbstractMinimalCostFlow,U>( move( G ) , Ring( one_U ) , infty ) {} template pair,U>>>> AbstractMinimalCostFlow::GetFlow( const inner_t& t_start , const inner_t& t_final , U f ) { using T = inner_t; const U& zero = m_R.Zero(); const U& infty = this->Infty(); const int& size = m_G.size(); vector>> rest( size ); vector>> flow( size ); int edge_num = 0; for( int i = 0 ; i < size ; i++ ){ auto&& ui = m_G.Enumeration( i ); auto&& edge_i = m_G.Edge( ui ); for( auto itr = edge_i.begin() , end = edge_i.end() ; itr != end ; itr++ ){ const auto& [vj,wj,fj] = *itr; assert( ui != vj && !( wj < zero ) && wj < infty && !( fj < zero ) && fj < infty ); auto&& j = m_G.Enumeration_inv( vj ); rest[i].push_back( { j , wj , fj , false , edge_num } ); rest[j].push_back( { i , m_R.Inverse( wj ) , zero , true , edge_num } ); flow[i].push_back( { vj , 0 } ); edge_num++; } } for( int i = 0 ; i < size ; i++ ){ auto& rest_i = rest[i]; sort( rest_i.begin() , rest_i.end() ); } vector> edge_pair( edge_num , { -1 , -1 , -1 , -1 } ); for( int i = 0 ; i < size ; i++ ){ const auto& rest_i = rest[i]; const int size_i = rest_i.size(); for( int j = 0 ; j < size_i ; j++ ){ const auto& rest_ij = rest_i[j]; auto& [i_0,j_0,i_1,j_1] = edge_pair[get<4>( rest_ij )]; if( i_0 == -1 ){ i_0 = i; j_0 = j; } else { i_1 = i; j_1 = j; } } } auto edge = [&]( const T& t ) -> const vector>& { return rest[m_G.Enumeration_inv( t )]; }; auto on = [&]( const tuple& e ) { return zero < get<2>( e ); }; auto G = m_G.GetGraph( move( edge ) ); AbstractPotentialisedDijkstra pd{ move( G ) , m_R.AdditiveGroup() , t_start , infty , move( on ) , false }; auto&& i_start = m_G.Enumeration_inv( t_start ); auto&& i_final = m_G.Enumeration_inv( t_final ); U w = zero; while( zero < f ){ auto [valid,weight,paths] = pd.GetPath(); assert( valid ); pd.SetPotential( valid , move( weight ) ); auto& path = paths[i_final]; auto itr_path = path.begin() , itr_path_prev = itr_path , end_path = path.end(); assert( itr_path != end_path ); int i = i_start; list> flow_num{}; U f_min = f; while( ++itr_path != end_path ){ T t = *itr_path; flow_num.push_back( { i , m_G.Enumeration_inv( t ) , -1 , -1 } ); auto& [i_curr,i_next,j_1,j_2] = flow_num.back(); const auto& rest_i = rest[i_curr]; int size_i = rest_i.size(); for( int j = 0 ; j < size_i ; j++ ){ const auto& [vj,wj,fj,rj,numj] = rest_i[j]; if( zero < fj && vj == t ){ j_1 = j; fj < f_min ? f_min = fj : f_min; if( rj ){ i_curr = i_next; t = *itr_path_prev; } break; } } assert( j_1 != -1 ); auto& flow_i = flow[i_curr]; size_i = flow_i.size(); for( int j = 0 ; j < size_i ; j++ ){ const auto& [vj,fj] = flow_i[j]; if( vj == t ){ j_2 = j; break; } } assert( j_2 != -1 ); i_curr = i; i = i_next; itr_path_prev = itr_path; } paths.clear(); const U f_min_minus = m_R.Inverse( f_min ); U w_diff = zero; for( auto itr = flow_num.begin() , end = flow_num.end() ; itr != end ; itr++ ){ const auto& [i_curr,i_next,j_1,j_2] = *itr; auto& [vj,wj,fj,rj,numj] = rest[i_curr][j_1]; const auto& edge_pair_i = edge_pair[numj]; const int& j_3 = get<0>( edge_pair_i ) == i_curr ? get<3>( edge_pair_i ) : get<1>( edge_pair_i ); auto& fj_inv = get<2>( rest[i_next][j_3] ); auto& f_curr = get<1>( flow[rj ? i_next : i_curr][j_2] ); w_diff = m_R.Sum( w_diff , wj ); fj = m_R.Sum( fj , f_min_minus ); fj_inv = m_R.Sum( fj_inv , f_min ); f_curr = m_R.Sum( f_curr , f_min ); } f = m_R.Sum( f , f_min_minus ); w = m_R.Sum( w , m_R.Product( f_min , w_diff ) ); } return { move( w ) , move( flow ) }; } // AAA 常設でないライブラリは以上に挿入する。 #define INCLUDE_SUB #include __FILE__ #else // INCLUDE_LIBRARY #ifdef DEBUG #define _GLIBCXX_DEBUG #define REPEAT_MAIN( BOUND ) START_MAIN; signal( SIGABRT , &AlertAbort ); AutoCheck( exec_mode , use_getline ); if( exec_mode == sample_debug_mode || exec_mode == submission_debug_mode || exec_mode == library_search_mode ){ return 0; } else if( exec_mode == experiment_mode ){ Experiment(); return 0; } else if( exec_mode == small_test_mode ){ SmallTest(); return 0; }; DEXPR( int , bound_test_case_num , BOUND , min( BOUND , 100 ) ); int test_case_num = 1; if( exec_mode == solve_mode ){ if constexpr( bound_test_case_num > 1 ){ SET_ASSERT( test_case_num , 1 , bound_test_case_num ); } } else if( exec_mode == random_test_mode ){ CERR( "ランダムテストを行う回数を指定してください。" ); SET_LL( test_case_num ); } FINISH_MAIN #define DEXPR( LL , BOUND , VALUE , DEBUG_VALUE ) CEXPR( LL , BOUND , DEBUG_VALUE ) #define ASSERT( A , MIN , MAX ) CERR( "ASSERTチェック: " , ( MIN ) , ( ( MIN ) <= A ? "<=" : ">" ) , A , ( A <= ( MAX ) ? "<=" : ">" ) , ( MAX ) ); assert( ( MIN ) <= A && A <= ( MAX ) ) #define SET_ASSERT( A , MIN , MAX ) if( exec_mode == solve_mode ){ SET_LL( A ); ASSERT( A , MIN , MAX ); } else if( exec_mode == random_test_mode ){ CERR( #A , " = " , ( A = GetRand( MIN , MAX ) ) ); } else { assert( false ); } #define SOLVE_ONLY static_assert( __FUNCTION__[0] == 'S' ) #define CERR( ... ) VariadicCout( cerr , __VA_ARGS__ ) << endl #define COUT( ... ) VariadicCout( cout << "出力: " , __VA_ARGS__ ) << endl #define CERR_A( A , N ) OUTPUT_ARRAY( cerr , A , N ) << endl #define COUT_A( A , N ) cout << "出力: "; OUTPUT_ARRAY( cout , A , N ) << endl #define CERR_ITR( A ) OUTPUT_ITR( cerr , A ) << endl #define COUT_ITR( A ) cout << "出力: "; OUTPUT_ITR( cout , A ) << endl #else #pragma GCC optimize ( "O3" ) #pragma GCC optimize ( "unroll-loops" ) #pragma GCC target ( "sse4.2,fma,avx2,popcnt,lzcnt,bmi2" ) #define REPEAT_MAIN( BOUND ) START_MAIN; CEXPR( int , bound_test_case_num , BOUND ); int test_case_num = 1; if constexpr( bound_test_case_num > 1 ){ SET_ASSERT( test_case_num , 1 , bound_test_case_num ); } FINISH_MAIN #define DEXPR( LL , BOUND , VALUE , DEBUG_VALUE ) CEXPR( LL , BOUND , VALUE ) #define ASSERT( A , MIN , MAX ) assert( ( MIN ) <= A && A <= ( MAX ) ) #define SET_ASSERT( A , MIN , MAX ) SET_LL( A ); ASSERT( A , MIN , MAX ) #define SOLVE_ONLY #define CERR( ... ) #define COUT( ... ) VariadicCout( cout , __VA_ARGS__ ) << ENDL #define CERR_A( A , N ) #define COUT_A( A , N ) OUTPUT_ARRAY( cout , A , N ) << ENDL #define CERR_ITR( A ) #define COUT_ITR( A ) OUTPUT_ITR( cout , A ) << ENDL #endif #ifdef REACTIVE #define ENDL endl #else #define ENDL "\n" #endif #ifdef USE_GETLINE #define SET_LL( A ) { GETLINE( A ## _str ); A = stoll( A ## _str ); } #define GETLINE_SEPARATE( SEPARATOR , ... ) SOLVE_ONLY; string __VA_ARGS__; VariadicGetline( cin , SEPARATOR , __VA_ARGS__ ) #define GETLINE( ... ) SOLVE_ONLY; GETLINE_SEPARATE( '\n' , __VA_ARGS__ ) #else #define SET_LL( A ) cin >> A #define CIN( LL , ... ) SOLVE_ONLY; LL __VA_ARGS__; VariadicCin( cin , __VA_ARGS__ ) #define SET_A( A , N ) SOLVE_ONLY; FOR( VARIABLE_FOR_CIN_A , 0 , N ){ cin >> A[VARIABLE_FOR_CIN_A]; } #define CIN_A( LL , A , N ) vector A( N ); SET_A( A , N ); #endif #include using namespace std; using uint = unsigned int; using ll = long long; using ull = unsigned long long; using ld = long double; using lld = __float128; template using T2 = pair; template using T3 = tuple; template using T4 = tuple; using path = pair; #define ATT __attribute__( ( target( "sse4.2,fma,avx2,popcnt,lzcnt,bmi2" ) ) ) #define START_MAIN int main(){ ios_base::sync_with_stdio( false ); cin.tie( nullptr ) #define FINISH_MAIN REPEAT( test_case_num ){ if constexpr( bound_test_case_num > 1 ){ CERR( "testcase " , VARIABLE_FOR_REPEAT_test_case_num , ":" ); } Solve(); CERR( "" ); } } #define START_WATCH chrono::system_clock::time_point watch = chrono::system_clock::now() #define CURRENT_TIME static_cast( chrono::duration_cast( chrono::system_clock::now() - watch ).count() / 1000.0 ) #define CHECK_WATCH( TL_MS ) ( CURRENT_TIME < TL_MS - 100.0 ) #define decldecay_t( VAR ) decay_t #define CEXPR( LL , BOUND , VALUE ) constexpr LL BOUND = VALUE #define CIN_ASSERT( A , MIN , MAX ) decldecay_t( MAX ) A; SET_ASSERT( A , MIN , MAX ) #define FOR( VAR , INITIAL , FINAL_PLUS_ONE ) for( decldecay_t( FINAL_PLUS_ONE ) VAR = INITIAL ; VAR < FINAL_PLUS_ONE ; VAR ++ ) #define FOREQ( VAR , INITIAL , FINAL ) for( decldecay_t( FINAL ) VAR = INITIAL ; VAR <= FINAL ; VAR ++ ) #define FOREQINV( VAR , INITIAL , FINAL ) for( decldecay_t( INITIAL ) VAR = INITIAL ; VAR + 1 > FINAL ; VAR -- ) #define AUTO_ITR( ARRAY ) auto itr_ ## ARRAY = ARRAY .begin() , end_ ## ARRAY = ARRAY .end() #define FOR_ITR( ARRAY ) for( AUTO_ITR( ARRAY ) , itr = itr_ ## ARRAY ; itr_ ## ARRAY != end_ ## ARRAY ; itr_ ## ARRAY ++ , itr++ ) #define REPEAT( HOW_MANY_TIMES ) FOR( VARIABLE_FOR_REPEAT_ ## HOW_MANY_TIMES , 0 , HOW_MANY_TIMES ) #define SET_PRECISION( DECIMAL_DIGITS ) cout << fixed << setprecision( DECIMAL_DIGITS ) #define OUTPUT_ARRAY( OS , A , N ) FOR( VARIABLE_FOR_OUTPUT_ARRAY , 0 , N ){ OS << A[VARIABLE_FOR_OUTPUT_ARRAY] << (VARIABLE_FOR_OUTPUT_ARRAY==N-1?"":" "); } OS #define OUTPUT_ITR( OS , A ) { auto ITERATOR_FOR_OUTPUT_ITR = A.begin() , END_FOR_OUTPUT_ITR = A.end(); bool VARIABLE_FOR_OUTPUT_ITR = ITERATOR_FOR_COUT_ITR != END_FOR_COUT_ITR; while( VARIABLE_FOR_OUTPUT_ITR ){ OS << *ITERATOR_FOR_COUT_ITR; ( VARIABLE_FOR_OUTPUT_ITR = ++ITERATOR_FOR_COUT_ITR != END_FOR_COUT_ITR ) ? OS : OS << " "; } } OS #define RETURN( ... ) SOLVE_ONLY; COUT( __VA_ARGS__ ); return #define COMPARE( ... ) auto naive = Naive( __VA_ARGS__ ); auto answer = Answer( __VA_ARGS__ ); bool match = naive == answer; COUT( "(" , #__VA_ARGS__ , ") == (" , __VA_ARGS__ , ") : Naive == " , naive , match ? "==" : "!=" , answer , "== Answer" ); if( !match ){ return; } // 入出力用 template inline basic_istream& VariadicCin( basic_istream& is ) { return is; } template inline basic_istream& VariadicCin( basic_istream& is , Arg& arg , ARGS&... args ) { return VariadicCin( is >> arg , args... ); } template inline basic_istream& VariadicGetline( basic_istream& is , const char& separator ) { return is; } template inline basic_istream& VariadicGetline( basic_istream& is , const char& separator , Arg& arg , ARGS&... args ) { return VariadicGetline( getline( is , arg , separator ) , separator , args... ); } template inline basic_ostream& operator<<( basic_ostream& os , const vector& arg ) { auto begin = arg.begin() , end = arg.end(); auto itr = begin; while( itr != end ){ ( itr == begin ? os : os << " " ) << *itr; itr++; } return os; } template inline basic_ostream& VariadicCout( basic_ostream& os , const Arg& arg ) { return os << arg; } template inline basic_ostream& VariadicCout( basic_ostream& os , const Arg1& arg1 , const Arg2& arg2 , const ARGS&... args ) { return VariadicCout( os << arg1 << " " , arg2 , args... ); } // デバッグ用 #ifdef DEBUG inline void AlertAbort( int n ) { CERR( "abort関数が呼ばれました。assertマクロのメッセージが出力されていない場合はオーバーフローの有無を確認をしてください。" ); } void AutoCheck( int& exec_mode , const bool& use_getline ); inline void Solve(); inline void Experiment(); inline void SmallTest(); inline void RandomTest(); ll GetRand( const ll& Rand_min , const ll& Rand_max ); int exec_mode; CEXPR( int , solve_mode , 0 ); CEXPR( int , sample_debug_mode , 1 ); CEXPR( int , submission_debug_mode , 2 ); CEXPR( int , library_search_mode , 3 ); CEXPR( int , experiment_mode , 4 ); CEXPR( int , small_test_mode , 5 ); CEXPR( int , random_test_mode , 6 ); #ifdef USE_GETLINE CEXPR( bool , use_getline , true ); #else CEXPR( bool , use_getline , false ); #endif #else ll GetRand( const ll& Rand_min , const ll& Rand_max ) { ll answer = time( NULL ); return answer * rand() % ( Rand_max + 1 - Rand_min ) + Rand_min; } #endif // 圧縮用 #define TE template #define TY typename #define US using #define ST static #define IN inline #define CL class #define PU public #define OP operator #define CE constexpr #define CO const #define NE noexcept #define RE return #define WH while #define VO void #define VE vector #define LI list #define BE begin #define EN end #define SZ size #define MO move #define TH this #define CRI CO int& #define CRUI CO uint& #define CRL CO ll& // VVV 常設ライブラリは以下に挿入する。 // Map // c:/Users/user/Documents/Programming/Mathematics/Function/Map CL is_ordered{PU:is_ordered()= delete;TE ST CE auto Check(CO T& t)-> decltype(t < t,true_type());ST CE false_type Check(...);TE ST CE CO bool value = is_same_v< decltype(Check(declval())),true_type >;}; TE US Map = conditional_t>,unordered_map,conditional_t,map,void>>; // AAA 常設ライブラリは以上に挿入する。 #define INCLUDE_LIBRARY #include __FILE__ #endif // INCLUDE_LIBRARY #endif // INCLUDE_SUB #endif // INCLUDE_MAIN