結果
問題 | No.2897 2集合間距離 |
ユーザー | 👑 p-adic |
提出日時 | 2024-03-14 19:14:23 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 357 ms / 3,500 ms |
コード長 | 31,509 bytes |
コンパイル時間 | 3,781 ms |
コンパイル使用メモリ | 242,364 KB |
実行使用メモリ | 27,484 KB |
最終ジャッジ日時 | 2024-09-20 20:50:14 |
合計ジャッジ時間 | 11,563 ms |
ジャッジサーバーID (参考情報) |
judge3 / judge2 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 160 ms
12,288 KB |
testcase_01 | AC | 170 ms
12,416 KB |
testcase_02 | AC | 154 ms
12,416 KB |
testcase_03 | AC | 169 ms
12,416 KB |
testcase_04 | AC | 170 ms
12,416 KB |
testcase_05 | AC | 175 ms
12,416 KB |
testcase_06 | AC | 176 ms
12,544 KB |
testcase_07 | AC | 173 ms
12,544 KB |
testcase_08 | AC | 170 ms
12,416 KB |
testcase_09 | AC | 181 ms
12,544 KB |
testcase_10 | AC | 184 ms
12,672 KB |
testcase_11 | AC | 181 ms
12,672 KB |
testcase_12 | AC | 185 ms
13,612 KB |
testcase_13 | AC | 201 ms
13,440 KB |
testcase_14 | AC | 220 ms
16,088 KB |
testcase_15 | AC | 212 ms
16,256 KB |
testcase_16 | AC | 330 ms
27,420 KB |
testcase_17 | AC | 335 ms
27,352 KB |
testcase_18 | AC | 346 ms
27,360 KB |
testcase_19 | AC | 340 ms
27,356 KB |
testcase_20 | AC | 357 ms
27,484 KB |
testcase_21 | AC | 279 ms
21,344 KB |
testcase_22 | AC | 251 ms
20,096 KB |
testcase_23 | AC | 272 ms
20,064 KB |
ソースコード
// 入力制約チェック #ifndef INCLUDE_MODE #define INCLUDE_MODE // #define REACTIVE // #define USE_GETLINE #endif #ifdef INCLUDE_MAIN inline void Solve() { // 入力受け取りとグラフの構築 // (実装は好きにして良いが全ての辺を前計算してメモリ上に置くと重くなることに注意) H = W = 1e3; H_minus = H - 1; W_minus = W - 1; HW = H * W; CEXPR( int , bound_N , 2e5 ); CIN_ASSERT( N , 1 , bound_N ); vector<int> xy( N ); vector<bool> in_xy( HW ); FOR( i , 0 , N ){ CIN_ASSERT( xi , 0 , W_minus ); CIN_ASSERT( yi , 0 , H_minus ); xy[i] = EnumHW_inv( {yi,xi} ); assert( !in_xy[xy[i]] ); in_xy[xy[i]] = true; } CEXPR( int , bound_M , 2e5 ); CIN_ASSERT( M , 1 , bound_M ); vector<bool> zw( HW ); FOR( j , 0 , M ){ CIN_ASSERT( zj , 0 , W_minus ); CIN_ASSERT( wj , 0 , H_minus ); int zwj = EnumHW_inv( {wj,zj} ); assert( !zw[zwj] ); zw[zwj] = true; } string S = ""; REPEAT( W ){ S += "."; } wall_str.resize( H , S ); auto edge = [&]( const int& v ){ vector<int> answer{}; if( v < HW ){ answer = EdgeOnGrid( v ); if( zw[v] ){ answer.push_back( HW + 1 ); } } else if ( v == HW ){ answer = xy; } return answer; }; Graph graph{ HW + 2 , edge }; // 幅優先探索で距離を計算(実装は好きにして良い) BreadthFirstSearch bfs{ graph , -1 , HW }; auto d = bfs.GetDistance(); // 答えの出力 RETURN( d[HW+1] - 2 ); } REPEAT_MAIN(1); #else // INCLUDE_MAIN #ifdef INCLUDE_LIBRARY // https://github.com/p-adic/cpp // VVV ライブラリは以下に挿入する。 class is_ordered { private: is_ordered() = delete; template <typename T> static constexpr auto Check( const T& t ) -> decltype( t < t , true_type() ); static constexpr false_type Check( ... ); public: template <typename T> static constexpr const bool value = is_same_v< decltype( Check( declval<T>() ) ) , true_type >; }; template <typename INT , template <typename...> typename T> struct hash<T<INT>> : public hash<INT> { inline size_t operator()( const T<INT>& n ) const; }; template <typename T , typename U> using Map = conditional_t<is_constructible_v<unordered_map<T,int>>,unordered_map<T,U>,conditional_t<is_ordered::value<T>,map<T,U>,void>>; // Map<T,U>は // - unordered_map<T,U>()がwell-formedならばunordered_map<T,U> // - そうでなくoperator<(declval<T>(),declval<T>())がwell-formedならばmap<T,U> // - そうでないならばvoid template <typename INT , template <typename...> typename T> inline size_t hash<T<INT>>::operator()( const T<INT>& n ) const { return hash<INT>::operator()( n.Represent() ); } #define DECLARATION_OF_CPOINT( POINT ) inline const U& POINT() const noexcept #define DECLARATION_OF_POINT( POINT ) inline U& POINT() noexcept #define DEFINITION_OF_CPOINT( POINT ) template <typename U> inline const U& VirtualPointedSet<U>::POINT() const noexcept { return Point(); } #define DEFINITION_OF_POINT( POINT ) template <typename U> inline U& VirtualPointedSet<U>::POINT() noexcept { return Point(); } // - インタフェースをなるべく抽象型で与えて仮想継承する。 // - 具体的構造が2種類以上あるものはもちろん抽象型を仮想継承する。 // - VirtualPointedSetのように具体的構造が1種類しかないものも仮想継承のコンストラクタ呼び出しを // 省略するためになるべく抽象型を用意する。 // - AbstractDijkstraのように全ての具体的構造が1つの具体的構造の派生である場合は // インタフェースを必要としない。 // - コンストラクタはなるべく省略できるようにするが、ポインタはメンバ変数にしない。 // - VirtualGraphのように具体的構造が2種類以上あるもので全てに共通の定義本体を持つ関数(Edge)が // 必要な場合は実装が膨れ上がらないように抽象型に関数の定義をし、そのため抽象型にメンバ変数が // 必要になる場合はコンストラクタを非自明なものにする // - 代わりにポインタを抽象型のメンバとして // 派生クラスのコンストラクタの定義内でアドレスを渡すようにすると、ムーブなどで意図せず // ポインタの指すアドレスが意図通りでなくなることに注意する。 // - データ構造に渡すことを想定する。 // - データ構造の配列や初期化をムーブセマンティクスで処理できるようにするために // 代数構造もムーブコンストラクタがdeleteされないようにする。 // - そのために演算に対応する関数オブジェクトは参照ではなく実体としてメンバに持つ。 template <typename U> class UnderlyingSet { public: using type = U; }; template <typename U> class VirtualPointedSet : virtual public UnderlyingSet<U> { public: virtual const U& Point() const noexcept = 0; virtual U& Point() noexcept = 0; DECLARATION_OF_CPOINT( Unit ); DECLARATION_OF_CPOINT( Zero ); DECLARATION_OF_CPOINT( One ); DECLARATION_OF_CPOINT( Infty ); DECLARATION_OF_POINT( init ); DECLARATION_OF_POINT( root ); }; template <typename U> class PointedSet : virtual public VirtualPointedSet<U> { private: U m_b_U; public: inline PointedSet( const U& b_u = U() ); inline const U& Point() const noexcept; inline U& Point() noexcept; }; template <typename U> class VirtualNSet : virtual public UnderlyingSet<U> { public: virtual U Transfer( const U& u ) = 0; inline U Inverse( const U& u ); }; template <typename U , typename F_U> class AbstractNSet : virtual public VirtualNSet<U> { private: F_U m_f_U; public: inline AbstractNSet( F_U f_U ); inline U Transfer( const U& u ); }; template <typename U> class VirtualMagma : virtual public UnderlyingSet<U> { public: virtual U Product( const U& u0 , const U& u1 ) = 0; inline U Sum( const U& u0 , const U& u1 ); }; template <typename U = ll> class AdditiveMagma : virtual public VirtualMagma<U> { public: inline U Product( const U& u0 , const U& u1 ); }; template <typename U = ll> class MultiplicativeMagma : virtual public VirtualMagma<U> { public: inline U Product( const U& u0 , const U& u1 ); }; template <typename U , typename M_U> class AbstractMagma : virtual public VirtualMagma<U> { private: M_U m_m_U; public: inline AbstractMagma( M_U m_U ); inline U Product( const U& u0 , const U& u1 ); }; template <typename U> inline PointedSet<U>::PointedSet( const U& b_U ) : m_b_U( b_U ) {} template <typename U> inline const U& PointedSet<U>::Point() const noexcept { return m_b_U; } template <typename U> inline U& PointedSet<U>::Point() noexcept { return m_b_U; } DEFINITION_OF_CPOINT( Unit ); DEFINITION_OF_CPOINT( Zero ); DEFINITION_OF_CPOINT( One ); DEFINITION_OF_CPOINT( Infty ); DEFINITION_OF_POINT( init ); DEFINITION_OF_POINT( root ); template <typename U , typename F_U> inline AbstractNSet<U,F_U>::AbstractNSet( F_U f_U ) : m_f_U( move( f_U ) ) { static_assert( is_invocable_r_v<U,F_U,U> ); } template <typename U , typename F_U> inline U AbstractNSet<U,F_U>::Transfer( const U& u ) { return m_f_U( u ); } template <typename U> inline U VirtualNSet<U>::Inverse( const U& u ) { return Transfer( u ); } template <typename U , typename M_U> inline AbstractMagma<U,M_U>::AbstractMagma( M_U m_U ) : m_m_U( move( m_U ) ) { static_assert( is_invocable_r_v<U,M_U,U,U> ); } template <typename U> inline U AdditiveMagma<U>::Product( const U& u0 , const U& u1 ) { return u0 + u1; } template <typename U> inline U MultiplicativeMagma<U>::Product( const U& u0 , const U& u1 ) { return u0 * u1; } template <typename U , typename M_U> inline U AbstractMagma<U,M_U>::Product( const U& u0 , const U& u1 ) { return m_m_U( u0 , u1 ); } template <typename U> inline U VirtualMagma<U>::Sum( const U& u0 , const U& u1 ) { return Product( u0 , u1 ); } // グラフ用 #ifndef RET_TYPE #define RET_TYPE template <typename F , typename...Args> using ret_t = decltype( declval<F>()( declval<Args>()... ) ); #endif #ifndef INNER_TYPE #define INNER_TYPE template <typename T> using inner_t = typename T::type; #endif // Enumeration:N->R1-->TとEnumeration_inv:T->R2-->Nは互いに逆写像である仮想関数。 template <typename T , typename R1 , typename R2 , typename E> class VirtualGraph : virtual public UnderlyingSet<T> { public: virtual R1 Enumeration( const int& i ) = 0; inline R2 Enumeration_inv( const T& t ); template <typename PATH> inline R2 Enumeration_inv( const PATH& p ); inline void Reset(); virtual const int& size() const noexcept = 0; virtual E& edge() noexcept = 0; virtual ret_t<E,T> Edge( const T& t ) = 0; private: virtual inline R2 Enumeration_inv_Body( const T& t ) = 0; }; template <typename T , typename R1 , typename R2 , typename E> class EdgeImplimentation : virtual public VirtualGraph<T,R1,R2,E> { private: int m_size; // 配列への参照を返す関数オブジェクトを構築して返す関数の返り値などの右辺値を受け取ることを // 許容したいので左辺値参照にはしない。 E m_edge; public: inline EdgeImplimentation( const int& size , E edge ); inline const int& size() const noexcept; inline E& edge() noexcept; inline ret_t<E,T> Edge( const T& t ); }; template <typename E> class Graph : public EdgeImplimentation<int,const int&,const int&,E> { public: inline Graph( const int& size , E edge ); inline const int& Enumeration( const int& i ); template <typename F> inline Graph<F> GetGraph( F edge ) const; private: inline const int& Enumeration_inv_Body( const int& t ); }; template <typename T , typename Enum_T , typename Enum_T_inv , typename E> class EnumerationGraph : public EdgeImplimentation<T,ret_t<Enum_T,int>,ret_t<Enum_T_inv,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<Enum_T,int> Enumeration( const int& i ); template <typename F> inline EnumerationGraph<T,Enum_T,Enum_T_inv,F> GetGraph( F edge ) const; private: inline ret_t<Enum_T_inv,T> Enumeration_inv_Body( const T& t ); }; template <typename Enum_T , typename Enum_T_inv , typename E> EnumerationGraph( const int& size , Enum_T enum_T , Enum_T_inv enum_T_inv , E edge ) -> EnumerationGraph<decldecay_t(declval<Enum_T>()(0)),Enum_T,Enum_T_inv,E>; // 推論補助のためにE::operator()はデフォルト引数が必要。 template <typename T , typename E> class MemorisationGraph : public EdgeImplimentation<T,T,const int&,E> { private: int m_length; vector<T> m_memory; Map<T,int> m_memory_inv; public: inline MemorisationGraph( const int& size , E edge ); // push_backする可能性のあるvectorなので参照にしないように注意 inline T Enumeration( const int& i ); inline void Reset(); template <typename F> inline MemorisationGraph<T,F> GetGraph( F edge ) const; private: inline const int& Enumeration_inv_Body( const T& t ); }; template <typename E> MemorisationGraph( const int& size , E edge ) -> MemorisationGraph<decldecay_t(declval<E>()().back()),E>; template <typename E> MemorisationGraph( const int& size , E edge ) -> MemorisationGraph<decldecay_t(get<0>(declval<E>()().back())),E>; template <typename T , typename R1 , typename R2 , typename E> inline EdgeImplimentation<T,R1,R2,E>::EdgeImplimentation( const int& size , E edge ) : m_size( size ) , m_edge( move( edge ) ) { static_assert( is_constructible_v<T,R1> && is_constructible_v<int,R2> && is_invocable_v<E,T> ); } template <typename E> inline Graph<E>::Graph( const int& size , E edge ) : EdgeImplimentation<int,const int&,const int&,E>( size , move( edge ) ) {} template <typename T , typename Enum_T , typename Enum_T_inv , typename E> inline EnumerationGraph<T,Enum_T,Enum_T_inv,E>::EnumerationGraph( const int& size , Enum_T enum_T , Enum_T_inv enum_T_inv , E edge ) : EdgeImplimentation<T,ret_t<Enum_T,int>,ret_t<Enum_T_inv,T>,E>( size , move( edge ) ) , m_enum_T( move( enum_T ) ) , m_enum_T_inv( move( enum_T_inv ) ) {} template <typename T , typename E> inline MemorisationGraph<T,E>::MemorisationGraph( const int& size , E edge ) : EdgeImplimentation<T,T,const int&,E>( size , move( edge ) ) , m_length() , m_memory() , m_memory_inv() { static_assert( is_invocable_v<E> && is_invocable_v<E,T> ); } template <typename E> inline const int& Graph<E>::Enumeration( const int& i ) { return i; } template <typename T , typename Enum_T , typename Enum_T_inv , typename E> inline ret_t<Enum_T,int> EnumerationGraph<T,Enum_T,Enum_T_inv,E>::Enumeration( const int& i ) { return m_enum_T( i ); } template <typename T , typename E> inline T MemorisationGraph<T,E>::Enumeration( const int& i ) { assert( 0 <= i && i < m_length ); return m_memory[i]; } template <typename T , typename R1 , typename R2 , typename E> inline R2 VirtualGraph<T,R1,R2,E>::Enumeration_inv( const T& t ) { return Enumeration_inv_Body( t ); } template <typename T , typename R1 , typename R2 , typename E> template <typename PATH> inline R2 VirtualGraph<T,R1,R2,E>::Enumeration_inv( const PATH& p ) { return Enumeration_inv_Body( get<0>( p ) ); } template <typename E> inline const int& Graph<E>::Enumeration_inv_Body( const int& i ) { return i; } template <typename T , typename Enum_T , typename Enum_T_inv , typename E> inline ret_t<Enum_T_inv,T> EnumerationGraph<T,Enum_T,Enum_T_inv,E>::Enumeration_inv_Body( const T& t ) { return m_enum_T_inv( t ); } template <typename T , typename E> inline const int& MemorisationGraph<T,E>::Enumeration_inv_Body( 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 <typename T , typename R1 , typename R2 , typename E> void VirtualGraph<T,R1,R2,E>::Reset() {} template <typename T , typename E> inline void MemorisationGraph<T,E>::Reset() { m_length = 0; m_memory.clear(); m_memory_inv.clear(); } template <typename T , typename R1 , typename R2 , typename E> inline const int& EdgeImplimentation<T,R1,R2,E>::size() const noexcept { return m_size; } template <typename T , typename R1 , typename R2 , typename E> inline E& EdgeImplimentation<T,R1,R2,E>::edge() noexcept { return m_edge; } template <typename T , typename R1 , typename R2 , typename E> inline ret_t<E,T> EdgeImplimentation<T,R1,R2,E>::Edge( const T& t ) { return m_edge( t ); } template <typename E> template <typename F> inline Graph<F> Graph<E>::GetGraph( F edge ) const { return Graph<F>( this->size() , move( edge ) ); } template <typename T , typename Enum_T , typename Enum_T_inv , typename E> template <typename F> inline EnumerationGraph<T,Enum_T,Enum_T_inv,F> EnumerationGraph<T,Enum_T,Enum_T_inv,E>::GetGraph( F edge ) const { return EnumerationGraph( this->size() , m_enum_T , m_enum_T_inv , move( edge ) ); } template <typename T , typename E> template <typename F> inline MemorisationGraph<T,F> MemorisationGraph<T,E>::GetGraph( F edge ) const { return MemorisationGraph( this->size() , move( edge ) ); } template <typename T , template <typename...> typename V> inline auto Get( const V<T>& a ) { return [&]( const int& i = 0 ){ return a[i]; }; } // グリッド問題用 int H , W , H_minus , W_minus , HW; vector<string> wall_str; char walkable = '.' , unwalkable = '#'; inline T2<int> EnumHW( const int& v ) { return { v / W , v % W }; } inline int EnumHW_inv( const T2<int>& ij ) { auto& [i,j] = ij; return i * W + j; } inline vector<int> EdgeOnGrid( const int& v ){vector<int>answer{};auto[i,j]=EnumHW(v);if(i>0&&wall_str[i-1][j]==walkable){answer.push_back(EnumHW_inv({i-1,j}));}if(i+1<H&&wall_str[i+1][j]==walkable){answer.push_back(EnumHW_inv({i+1,j}));}if(j>0&&wall_str[i][j-1]==walkable){answer.push_back(EnumHW_inv({i,j-1}));}if(j+1<W&&wall_str[i][j+1]==walkable){answer.push_back(EnumHW_inv({i,j+1}));}return answer;} // GRAPHは辺Edge:T->(T \times ...)^{< \omega}を持つグラフに相当する型。 // 構築 O(1)/O(|V_G|)(未初期化/初期化) // Next()の反復でinitから到達可能な頂点を全探索 O(initの連結成分における辺の本数) // Next()の反復とShift()で全探索 O(|V_G|+|E_G|) // initからの到達可能性判定と深さ計算 O(initの連結成分における辺の本数) // 連結成分の色分けと数え上げ O(|V_G|+|E_G|) template <typename T , typename GRAPH> class VirtualBreadthFirstSearch { protected: GRAPH& m_G; // 未訪問点のm_prevに格納するための変数。m_nextが空の時のNext()の戻り値。 T m_not_found; bool m_initialised; // 次の探索点たちを格納。 list<T> m_next; // 以下GRAPHがGraphでない場合は添字にEnumerationが絡むことに注意。 // m_nextに格納されたことがあるか否か。 vector<bool> m_found; // 到達済みかつ到達済みの点から辺を辿ってNext()で到達した場合、その点を格納。 // GRAPHがGraphでない場合は添字にEnumerationが絡むことに注意。 vector<T> m_prev; public: inline VirtualBreadthFirstSearch( GRAPH& G , const T& not_found ); template <typename Arg> inline VirtualBreadthFirstSearch( GRAPH& G , const T& not_found , Arg&& init ); // m_nextとm_foundとm_prevを初期化する。 inline void Initialise(); // m_nextとm_foundとm_prevを初期化した上でinitを最初の探索点に設定する。 inline void Initialise( const T& init ); inline void Initialise( list<T> inits ); // m_nextを初期化した上でm_foundとm_prevを非初期化せずinitを次の探索点に設定する。 inline void Shift( const T& init ); inline void Shift( list<T> inits ); inline const int& size() const noexcept; inline vector<bool>::reference found( const T& t ); inline const T& prev( const T& t ); inline T Next(); // 以下T==intかつGRAPHがGraphである場合にのみサポート。 // m_nextに格納されている未到達点(初期化時点ではinit/inits)から到達できる未到達点の深さを格納し、 // 到達できない未到達点や既到達点は深さの代わりに-1を格納。 vector<int> GetDistance(); // 無向グラフである場合にのみサポート。 // 未到達点の全体のなす部分グラフにおける連結成分の色分けと連結成分数を格納。 void SetConnectedComponent( vector<int>& cc_num , int& count ); private: virtual void Push( list<T>& next , const T& t ) = 0; template <typename PATH> inline void Push( list<T>& next , const PATH& p ); }; template <typename T , typename GRAPH> class BreadthFirstSearch : public VirtualBreadthFirstSearch<T,GRAPH> { public: template <typename...Args> inline BreadthFirstSearch( GRAPH& G , const T& not_found , Args&&... args ); private: inline void Push( list<T>& next , const T& t ); }; template <typename T , typename GRAPH> inline VirtualBreadthFirstSearch<T,GRAPH>::VirtualBreadthFirstSearch( GRAPH& G , const T& not_found ) : m_G( G ) , m_not_found( not_found ) , m_initialised( false ) , m_next() , m_found() , m_prev() {} template <typename T , typename GRAPH> template <typename Arg> inline VirtualBreadthFirstSearch<T,GRAPH>::VirtualBreadthFirstSearch( GRAPH& G , const T& not_found , Arg&& init ) : VirtualBreadthFirstSearch<T,GRAPH>( G , not_found ) { Initialise( forward<Arg>( init ) ); } template <typename T , typename GRAPH> inline void VirtualBreadthFirstSearch<T,GRAPH>::Initialise() { m_initialised = true; const int& V = size(); m_next.clear(); m_found = vector<bool>( V ); m_prev = vector<T>( V , m_not_found ); } template <typename T , typename GRAPH> inline void VirtualBreadthFirstSearch<T,GRAPH>::Initialise( const T& init ) { auto&& i = m_G.Enumeration_inv( init ); assert( 0 <= i && i < size() ); Initialise(); m_next.push_back( init ); m_found[i] = true; } template <typename T , typename GRAPH> inline void VirtualBreadthFirstSearch<T,GRAPH>::Initialise( list<T> inits ) { Initialise(); m_next = move( inits ); const int& V = size(); for( auto itr = m_next.begin() , end = m_next.end() ; itr != end ; itr++ ){ auto&& i = m_G.Enumeration_inv( *itr ); assert( 0 <= i && i < V ); m_found[i] = true; } } template <typename T , typename GRAPH> inline void VirtualBreadthFirstSearch<T,GRAPH>::Shift( const T& init ) { if( m_initialised ){ const int& V = size(); auto&& i = m_G.Enumeration_inv( init ); assert( 0 <= i && i < V ); m_next.clear(); if( ! m_found[i] ){ m_next.push_back( init ); m_found[i] = true; } } else { Initialise( init ); } } template <typename T , typename GRAPH> inline void VirtualBreadthFirstSearch<T,GRAPH>::Shift( list<T> inits ) { if( m_initialised ){ m_next.clear(); const int& V = size(); for( auto itr = m_next.begin() , end = m_next.end() ; itr != end ; itr++ ){ auto&& i = m_G.Enumeration_inv( *itr ); assert( 0 <= i && i < V ); if( ! m_found[i] ){ m_next.push_back( *itr ); m_found[i] = true; } } } else { Initialise( move( inits ) ); } } template <typename T , typename GRAPH> inline const int& VirtualBreadthFirstSearch<T,GRAPH>::size() const noexcept { return m_G.size(); } template <typename T , typename GRAPH> inline vector<bool>::reference VirtualBreadthFirstSearch<T,GRAPH>::found( const T& t ) { auto&& i = m_G.Enumeration_inv( t ); assert( 0 <= i && i < size() ); if( !m_initialised ){ Initialise(); } return m_found[i]; } template <typename T , typename GRAPH> inline const T& VirtualBreadthFirstSearch<T,GRAPH>::prev( const T& t ) { auto&& i = m_G.Enumeration_inv( t ); assert( 0 <= i && i < size() ); if( !m_initialised ){ Initialise(); } return m_prev[i]; } template <typename T , typename GRAPH> inline T VirtualBreadthFirstSearch<T,GRAPH>::Next() { if( m_next.empty() ){ return m_not_found; } const T t_curr = m_next.front(); m_next.pop_front(); auto&& edge = m_G.Edge( t_curr ); for( auto& t : edge ){ auto&& i = m_G.Enumeration_inv( t ); auto&& found_i = m_found[i]; if( ! found_i ){ Push( m_next , t ); m_prev[i] = t_curr; found_i = true; } } return t_curr; } template <typename T , typename GRAPH> vector<int> VirtualBreadthFirstSearch<T,GRAPH>::GetDistance() { static_assert( is_same_v<T,int> && is_same_v<GRAPH,Graph<decldecay_t( m_G.edge() )>> ); vector<int> depth{}; depth = vector<int>( size() , -1 ); for( auto itr = m_next.begin() , end = m_next.end() ; itr != end ; itr++ ){ depth[*itr] = 0; } int i; while( ( i = Next() ) != m_not_found ){ int& depth_i = depth[i]; depth_i == -1 ? depth_i = depth[prev( i )] + 1 : depth_i; } return depth; } template <typename T , typename GRAPH> void VirtualBreadthFirstSearch<T,GRAPH>::SetConnectedComponent( vector<int>& cc_num , int& count ) { static_assert( is_same_v<T,int> && is_same_v<GRAPH,Graph<decldecay_t( m_G.edge() )>> ); const int& V = size(); cc_num = vector<int>( V , -1 ); count = 0; for( int i = 0 ; i < V ; i++ ){ if( cc_num[i] == -1 ){ Shift( i ); int j = Next(); if( j != m_not_found ){ while( j != m_not_found ){ // 無向グラフである場合は常にtrue。 assert( cc_num[j] == -1 ); cc_num[j] = count; j = Next(); } count++; } } } return; } template <typename T , typename GRAPH> template <typename PATH> inline void VirtualBreadthFirstSearch<T,GRAPH>::Push( list<T>& next , const PATH& p ) { Push( next , get<0>( p ) ); } template <typename T , typename GRAPH> template <typename...Args> inline BreadthFirstSearch<T,GRAPH>::BreadthFirstSearch( GRAPH& G , const T& not_found , Args&&... args ) : VirtualBreadthFirstSearch<T,GRAPH>( G , not_found , forward<Args>( args )... ) {} template <typename T , typename GRAPH> inline void BreadthFirstSearch<T,GRAPH>::Push( list<T>& next , const T& t ) { next.push_back( t ); } // AAA ライブラリは以上に挿入する。 #define INCLUDE_MAIN #include __FILE__ #else // INCLUDE_LIBRARY #ifdef DEBUG #define _GLIBCXX_DEBUG #define SIGNAL signal( SIGABRT , &AlertAbort ); #define DEXPR( LL , BOUND , VALUE1 , VALUE2 ) CEXPR( LL , BOUND , VALUE2 ) #define ASSERT( A , MIN , MAX ) CERR( "ASSERTチェック: " , ( MIN ) , ( ( MIN ) <= A ? "<=" : ">" ) , A , ( A <= ( MAX ) ? "<=" : ">" ) , ( MAX ) ); assert( ( MIN ) <= A && A <= ( MAX ) ) #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 SIGNAL #define DEXPR( LL , BOUND , VALUE1 , VALUE2 ) CEXPR( LL , BOUND , VALUE1 ) #define ASSERT( A , MIN , MAX ) assert( ( MIN ) <= A && A <= ( MAX ) ) #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 , ... ) string __VA_ARGS__; VariadicGetline( cin , SEPARATOR , __VA_ARGS__ ) #define GETLINE( ... ) GETLINE_SEPARATE( '\n' , __VA_ARGS__ ) #else #define SET_LL( A ) cin >> A #define CIN( LL , ... ) LL __VA_ARGS__; VariadicCin( cin , __VA_ARGS__ ) #define SET_A( A , N ) FOR( VARIABLE_FOR_SET_A , 0 , N ){ cin >> A[VARIABLE_FOR_SET_A]; } #define CIN_A( LL , A , N ) vector<LL> A( N ); SET_A( A , N ); #endif #include <bits/stdc++.h> using namespace std; #define REPEAT_MAIN( BOUND ) int main(){ ios_base::sync_with_stdio( false ); cin.tie( nullptr ); SIGNAL; CEXPR( int , bound_test_case_num , BOUND ); int test_case_num = 1; if constexpr( bound_test_case_num > 1 ){ CERR( "テストケースの個数を入力してください。" ); SET_ASSERT( test_case_num , 1 , bound_test_case_num ); } 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<double>( chrono::duration_cast<chrono::microseconds>( chrono::system_clock::now() - watch ).count() / 1000.0 ) #define CHECK_WATCH( TL_MS ) ( CURRENT_TIME < TL_MS - 100.0 ) #define CEXPR( LL , BOUND , VALUE ) constexpr LL BOUND = VALUE #define SET_ASSERT( A , MIN , MAX ) SET_LL( A ); ASSERT( A , MIN , MAX ) #define SET_A_ASSERT( A , N , MIN , MAX ) FOR( VARIABLE_FOR_SET_A , 0 , N ){ SET_ASSERT( A[VARIABLE_FOR_SET_A] , MIN , MAX ); } #define CIN_ASSERT( A , MIN , MAX ) decldecay_t( MAX ) A; SET_ASSERT( A , MIN , MAX ) #define CIN_A_ASSERT( A , N , MIN , MAX ) vector<decldecay_t( MAX )> A( N ); SET_A_ASSERT( A , N , 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( ... ) COUT( __VA_ARGS__ ); return // 型のエイリアス #define decldecay_t( VAR ) decay_t<decltype( VAR )> template <typename F , typename...Args> using ret_t = decltype( declval<F>()( declval<Args>()... ) ); template <typename T> using inner_t = typename T::type; using uint = unsigned int; using ll = long long; using ull = unsigned long long; using ld = long double; using lld = __float128; template <typename INT> using T2 = pair<INT,INT>; template <typename INT> using T3 = tuple<INT,INT,INT>; template <typename INT> using T4 = tuple<INT,INT,INT,INT>; using path = pair<int,ll>; // 入出力用 template <class Traits> inline basic_istream<char,Traits>& VariadicCin( basic_istream<char,Traits>& is ) { return is; } template <class Traits , typename Arg , typename... ARGS> inline basic_istream<char,Traits>& VariadicCin( basic_istream<char,Traits>& is , Arg& arg , ARGS&... args ) { return VariadicCin( is >> arg , args... ); } template <class Traits> inline basic_istream<char,Traits>& VariadicGetline( basic_istream<char,Traits>& is , const char& separator ) { return is; } template <class Traits , typename Arg , typename... ARGS> inline basic_istream<char,Traits>& VariadicGetline( basic_istream<char,Traits>& is , const char& separator , Arg& arg , ARGS&... args ) { return VariadicGetline( getline( is , arg , separator ) , separator , args... ); } template <class Traits , typename Arg> inline basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os , const vector<Arg>& arg ) { auto begin = arg.begin() , end = arg.end(); auto itr = begin; while( itr != end ){ ( itr == begin ? os : os << " " ) << *itr; itr++; } return os; } template <class Traits , typename Arg1 , typename Arg2> inline basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os , const pair<Arg1,Arg2>& arg ) { return os << arg.first << " " << arg.second; } template <class Traits , typename Arg> inline basic_ostream<char,Traits>& VariadicCout( basic_ostream<char,Traits>& os , const Arg& arg ) { return os << arg; } template <class Traits , typename Arg1 , typename Arg2 , typename... ARGS> inline basic_ostream<char,Traits>& VariadicCout( basic_ostream<char,Traits>& 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( bool& auto_checked ); #endif #define INCLUDE_LIBRARY #include __FILE__ #endif // INCLUDE_LIBRARY #endif // INCLUDE_MAIN