#ifndef INCLUDE_MODE #define INCLUDE_MODE // #define REACTIVE // #define USE_GETLINE #endif #ifdef INCLUDE_MAIN IN VO Solve() { CIN( int , N , K ); N += 2; gA>.resize( N ); FOR( i , 0 , N ){ CIN( ll , x , y ); gA>[i] = { x + y , x - y }; } auto k = [&]( const int& D ){ auto edge = [&]( const int& i = 0 ){ list answer{}; FOR( j , 0 , N ){ int x = abs( gA>[i].first - gA>[j].first ); int y = abs( gA>[i].second - gA>[j].second ); if( x < y ){ swap( x , y ); } answer.push_back( { j , ( x - 1 ) / D } ); } return answer; }; Graph graph{ N , edge }; // EnumerationGraph graph{ N , Id , Id , edge }; // MemorisationGraph graph{ N , edge }; // Dijkstra d{ graph }; AbstractDijkstra d{ graph , AdditiveMonoid<>() , 1LL<<62 }; return d.GetDistance( 0 , 1 ); }; BS4( answer , 1 , 1e5 , k( answer ) , K ); RETURN( answer ); } REPEAT_MAIN(1); #else // INCLUDE_MAIN #ifdef INCLUDE_SUB // グラフ用 TE Map gF; TE VE gA; TE VE> gE; TE TY V> IN auto Get( CO V& a ) { return [&]( CRI i = 0 ){ RE a[i]; }; } // COMPAREに使用。圧縮時は削除する。 ll Naive( int N , int M , int K ) { ll answer = N + M + K; return answer; } // COMPAREに使用。圧縮時は削除する。 ll Answer( ll N , ll M , ll K ) { // START_WATCH; ll answer = N + M + K; // // TLに準じる乱択や全探索。デフォルトの猶予は100.0[ms]。 // CEXPR( double , TL , 2000.0 ); // while( CHECK_WATCH( TL ) ){ // } return answer; } // 圧縮時は中身だけ削除する。 IN VO Experiment() { // CEXPR( int , bound , 10 ); // FOREQ( N , 0 , bound ){ // FOREQ( M , 0 , bound ){ // FOREQ( K , 0 , bound ){ // COUT( N , M , K , ":" , Naive( N , M , K ) ); // } // } // // cout << Naive( N ) << ",\n"[N==bound]; // } } // 圧縮時は中身だけ削除する。 IN VO SmallTest() { // CEXPR( int , bound , 10 ); // FOREQ( N , 0 , bound ){ // FOREQ( M , 0 , bound ){ // FOREQ( K , 0 , bound ){ // COMPARE( N , M , K ); // } // } // // COMPARE( N ); // } } #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 IntervalAddBIT c:/Users/user/Documents/Programming/Mathematics/SetTheory/DirectProduct/AffineSpace/BIT/IntervalAdd/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 常設でないライブラリは以下に挿入する。 #define DIJKSTRA_PREP( INITIALISE_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 ); \ INITIALISE_PREV; \ #define DIJKSTRA_BODY_1( SET_PREV ) \ weight[i_start] = zero; \ int i = i_start; \ \ for( int num = 0 ; num < size ; num++ ){ \ \ const U& weight_i = weight[i]; \ found[i] = true; \ 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 ); \ \ if( !found[j] ){ \ \ const U& edge_ij = get<1>( *itr ); \ U temp = m_M.Sum( weight_i , edge_ij ); \ assert( temp < infty ); \ U& weight_j = weight[j]; \ \ if( temp < weight_j ){ \ \ SET_PREV; \ weight_j = move( temp ); \ \ } \ \ } \ \ } \ \ U temp = infty; \ \ for( int j = 0 ; j < size ; j++ ){ \ \ if( !found[j] ){ \ \ U& weight_j = weight[j]; \ \ if( weight_j < temp ){ \ \ temp = weight_j; \ i = j; \ \ } \ \ } \ \ } \ \ } \ #define DIJKSTRA_BODY_2( CHECK_FINAL , SET_PREV ) \ set> vertex{}; \ vertex.insert( pair( weight[i_start] = zero , i_start ) ); \ \ 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 = get<1>( *itr ); \ U temp = m_M.Sum( weight_i , edge_ij ); \ assert( temp < infty ); \ U& weight_j = weight[j]; \ \ if( temp < weight_j ){ \ \ 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 ); \ \ } \ \ } \ #define DIJKSTRA_BODY( INITIALISE_PREV , CHECK_FINAL , SET_PREV ) \ DIJKSTRA_PREP( INITIALISE_PREV ); \ \ if( many_edges ){ \ \ DIJKSTRA_BODY_1( SET_PREV ); \ \ } else { \ \ DIJKSTRA_BODY_2( CHECK_FINAL , SET_PREV ); \ \ } \ // 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|個以下の和で表せるいかなる数よりも大きい。 // が成り立つ場合にのみサポート。 // 単一始点単一終点最短経路探索/経路復元なしO(min(|V_G|^2+|E_G|),(|V_G|+|E_G|)log |E_G|)) // 単一始点単一終点最短経路探索/経路復元ありO(min(|V_G|^2+|E_G|),(|V_G|+|E_G|)log |E_G|)) // 単一始点全終点最短経路探索/経路復元なしO(min(|V_G|^2+|E_G|),(|V_G|+|E_G|)log |E_G|)) // 単一始点全終点最短経路探索/経路復元ありO(|V_G|^2+|E_G|) template class AbstractDijkstra : public PointedSet { private: GRAPH& m_G; // コンストラクタに引数が必要なMultiplicativeMonoidなどはstaticメンバ関数による // 参照返しがしにくく、コンストラクタの返り値である右辺値を受け取ることを許容したいので // 左辺値参照にはしない。 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 , const bool& many_edges = true ); vector GetDistance( const inner_t& t_start , const bool& many_edges = true ); pair>> GetPath( const inner_t& t_start , const inner_t& t_final , const bool& many_edges = true ); template