// #define _GLIBCXX_DEBUG #pragma GCC optimize ( "O3" ) #pragma GCC target ( "avx" ) #include using namespace std; using uint = unsigned int; using ll = long long; #define TYPE_OF( VAR ) remove_const::type >::type #define UNTIE ios_base::sync_with_stdio( false ); cin.tie( nullptr ) #define CEXPR( LL , BOUND , VALUE ) constexpr const LL BOUND = VALUE #define CIN( LL , A ) LL A; cin >> A #define ASSERT( A , MIN , MAX ) assert( MIN <= A && A <= MAX ) #define CIN_ASSERT( A , MIN , MAX ) CIN( TYPE_OF( MAX ) , A ); ASSERT( A , MIN , MAX ) #define GETLINE( A ) string A; getline( cin , A ) #define GETLINE_SEPARATE( A , SEPARATOR ) string A; getline( cin , A , SEPARATOR ) #define FOR( VAR , INITIAL , FINAL_PLUS_ONE ) for( TYPE_OF( FINAL_PLUS_ONE ) VAR = INITIAL ; VAR < FINAL_PLUS_ONE ; VAR ++ ) #define FOREQ( VAR , INITIAL , FINAL ) for( TYPE_OF( FINAL ) VAR = INITIAL ; VAR <= FINAL ; VAR ++ ) #define FOREQINV( VAR , INITIAL , FINAL ) for( TYPE_OF( INITIAL ) VAR = INITIAL ; VAR >= FINAL ; VAR -- ) #define FOR_ITR( ARRAY , ITR , END ) for( auto ITR = ARRAY .begin() , END = ARRAY .end() ; ITR != END ; ITR ++ ) #define REPEAT( HOW_MANY_TIMES ) FOR( VARIABLE_FOR_REPEAT , 0 , HOW_MANY_TIMES ) #define QUIT return 0 // #define COUT( ANSWER ) cout << ( ANSWER ) << "\n"; #define COUT( ANSWER ) cout << ( ANSWER ) << endl; #define RETURN( ANSWER ) COUT( ANSWER ); QUIT #define DOUBLE( PRECISION , ANSWER ) cout << fixed << setprecision( PRECISION ) << ( ANSWER ) << "\n"; QUIT #define POWER( ANSWER , ARGUMENT , EXPONENT ) \ TYPE_OF( ARGUMENT ) ANSWER{ 1 }; \ { \ TYPE_OF( ARGUMENT ) ARGUMENT_FOR_SQUARE_FOR_POWER = ( ARGUMENT ); \ TYPE_OF( EXPONENT ) EXPONENT_FOR_SQUARE_FOR_POWER = ( EXPONENT ); \ while( EXPONENT_FOR_SQUARE_FOR_POWER != 0 ){ \ if( EXPONENT_FOR_SQUARE_FOR_POWER % 2 == 1 ){ \ ANSWER *= ARGUMENT_FOR_SQUARE_FOR_POWER; \ } \ ARGUMENT_FOR_SQUARE_FOR_POWER *= ARGUMENT_FOR_SQUARE_FOR_POWER; \ EXPONENT_FOR_SQUARE_FOR_POWER /= 2; \ } \ } \ #define POWER_MOD( ANSWER , ARGUMENT , EXPONENT , MODULO ) \ TYPE_OF( ARGUMENT ) ANSWER{ 1 }; \ { \ TYPE_OF( ARGUMENT ) ARGUMENT_FOR_SQUARE_FOR_POWER = ( MODULO + ( ARGUMENT ) % MODULO ) % MODULO; \ TYPE_OF( EXPONENT ) EXPONENT_FOR_SQUARE_FOR_POWER = ( EXPONENT ); \ while( EXPONENT_FOR_SQUARE_FOR_POWER != 0 ){ \ if( EXPONENT_FOR_SQUARE_FOR_POWER % 2 == 1 ){ \ ANSWER = ( ANSWER * ARGUMENT_FOR_SQUARE_FOR_POWER ) % MODULO; \ } \ ARGUMENT_FOR_SQUARE_FOR_POWER = ( ARGUMENT_FOR_SQUARE_FOR_POWER * ARGUMENT_FOR_SQUARE_FOR_POWER ) % MODULO; \ EXPONENT_FOR_SQUARE_FOR_POWER /= 2; \ } \ } \ #define FACTORIAL_MOD( ANSWER , ANSWER_INV , MAX_I , LENGTH , MODULO ) \ ll ANSWER[LENGTH]; \ ll ANSWER_INV[LENGTH]; \ { \ ll VARIABLE_FOR_PRODUCT_FOR_FACTORIAL = 1; \ ANSWER[0] = VARIABLE_FOR_PRODUCT_FOR_FACTORIAL; \ FOREQ( i , 1 , MAX_I ){ \ ANSWER[i] = ( VARIABLE_FOR_PRODUCT_FOR_FACTORIAL *= i ) %= MODULO; \ } \ POWER_MOD( FACTORIAL_MAX_INV , ANSWER[MAX_I] , MODULO - 2 , MODULO ); \ ANSWER_INV[MAX_I] = FACTORIAL_MAX_INV; \ FOREQINV( i , MAX_I - 1 , 0 ){ \ ANSWER_INV[i] = ( FACTORIAL_MAX_INV *= i + 1 ) %= MODULO; \ } \ } \ \ // 通常の二分探索 #define BS( ANSWER , MINIMUM , MAXIMUM , EXPRESSION , TARGET ) \ ll ANSWER = MAXIMUM; \ { \ ll VARIABLE_FOR_BINARY_SEARCH_L = MINIMUM; \ ll VARIABLE_FOR_BINARY_SEARCH_U = ANSWER; \ ll VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH = ( TARGET ) - ( EXPRESSION ); \ if( VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH == 0 ){ \ VARIABLE_FOR_BINARY_SEARCH_L = ANSWER; \ } else { \ ANSWER = ( VARIABLE_FOR_BINARY_SEARCH_L + VARIABLE_FOR_BINARY_SEARCH_U ) / 2; \ } \ while( VARIABLE_FOR_BINARY_SEARCH_L != ANSWER ){ \ VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH = ( TARGET ) - ( EXPRESSION ); \ if( VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH == 0 ){ \ VARIABLE_FOR_BINARY_SEARCH_L = ANSWER; \ break; \ } else { \ if( VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH > 0 ){ \ VARIABLE_FOR_BINARY_SEARCH_L = ANSWER; \ } else { \ VARIABLE_FOR_BINARY_SEARCH_U = ANSWER; \ } \ ANSWER = ( VARIABLE_FOR_BINARY_SEARCH_L + VARIABLE_FOR_BINARY_SEARCH_U ) / 2; \ } \ } \ } \ \ // 二進法の二分探索 #define BS2( ANSWER , MINIMUM , MAXIMUM , EXPRESSION , TARGET ) \ ll ANSWER = MINIMUM; \ { \ ll VARIABLE_FOR_POWER_FOR_BINARY_SEARCH_2 = 1; \ ll VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH = ( MAXIMUM ) - ANSWER; \ while( VARIABLE_FOR_POWER_FOR_BINARY_SEARCH_2 <= VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH ){ \ VARIABLE_FOR_POWER_FOR_BINARY_SEARCH_2 *= 2; \ } \ VARIABLE_FOR_POWER_FOR_BINARY_SEARCH_2 /= 2; \ ll VARIABLE_FOR_ANSWER_FOR_BINARY_SEARCH_2 = ANSWER; \ while( VARIABLE_FOR_POWER_FOR_BINARY_SEARCH_2 != 0 ){ \ ANSWER = VARIABLE_FOR_ANSWER_FOR_BINARY_SEARCH_2 + VARIABLE_FOR_POWER_FOR_BINARY_SEARCH_2; \ VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH = ( TARGET ) - ( EXPRESSION ); \ if( VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH == 0 ){ \ VARIABLE_FOR_ANSWER_FOR_BINARY_SEARCH_2 = ANSWER; \ break; \ } else if( VARIABLE_FOR_DIFFERENCE_FOR_BINARY_SEARCH > 0 ){ \ VARIABLE_FOR_ANSWER_FOR_BINARY_SEARCH_2 = ANSWER; \ } \ VARIABLE_FOR_POWER_FOR_BINARY_SEARCH_2 /= 2; \ } \ ANSWER = VARIABLE_FOR_ANSWER_FOR_BINARY_SEARCH_2; \ } \ \ template inline T Absolute( const T& a ){ return a > 0 ? a : - a; } template inline T Residue( const T& a , const T& p ){ return a >= 0 ? a % p : p - ( - a - 1 ) % p - 1; } #define first1 first.first #define second1 first.second #define third1 second #define first2 first1 #define second2 second1 #define third2 second.first #define fourth2 second.second inline CEXPR( int , bound_N , 50000 ); // lazy_segtree用のデータ1 using S1_12 = pair; using S1 = pair; inline S1 op1( S1 a , S1 b ) { return S1( S1_12( a.first1 + b.first1 , a.second1 + b.second1 ) , a.third1 + b.third1 ); } inline S1 unit1() { return S1(); } using F1 = int; // vが(A,Ax,Ax^2)の形のベクトルの時にfvが(A,A(x+f),A(x+f)^2)=(A,Ax+fA,Ax^2+2fAx+f^2A)となるようなモノイド作用 inline S1 act1( F1 f , S1 v ) { return S1( S1_12( v.first1 , v.second1 + f * v.first1 ) , v.third1 + ( f * 2 ) * v.second1 + ( f * f ) * v.first1 ); } inline F1 comp1( F1 f1 , F1 f2 ) { return f1 + f2; } inline F1 id1() { return 0; } // lazy_segtree用のデータ2 using S2_12 = pair; using S2_34 = pair; using S2 = pair; inline S2 op2( S2 a , S2 b ) { return S2( S2_12( a.first2 + b.first2 , a.second2 + b.second2 ) , S2_34( a.third2 + b.third2 , a.fourth2 + b.fourth2 ) ); } inline S2 unit2() { return S2(); } using F2 = pair; // vが(A,Ax,Ay,Axy)の形のベクトルの時に(f_1,f_2)vが(A,A(x+f_1),A(y+f_2),A(x+f_1)(y+f_2))=(A,Ax+f_1A,Ay+f_2A,Axy+f_1Ay+f_2Ax+f_1f_2A)となるようなモノイド作用 inline S2 act2( F2 f , S2 v ) { return S2( S2_12( v.first2 , v.second2 + f.first * v.first2 ) , S2_34( v.third2 + f.second * v.first2 , v.fourth2 + f.first * v.third2 + f.second * v.second2 + ( f.first * f.second ) * v.first2 ) ); } inline F2 comp2( F2 f1 , F2 f2 ) { return F2( f1.first + f2.first , f1.second + f2.second ); } inline F2 id2() { return F2(); } // lazy_segtree用のデータ3 using S3 = ll; inline S3 op3( S3 a , S3 b ) { return a + b; } inline S3 unit3() { return 0; } using F3 = int; inline S3 act3( F3 f , S3 v ) { return f + v; } inline F3 comp3( F3 f1 , F3 f2 ) { return f1 + f2; } inline F3 id3() { return 0; } using Interval = pair; #include using namespace atcoder; // // Xの総和を計算するための、部分木におけるS内の総和の計算 // ll sum_v3( int v , list ( &children )[bound_N+1] , int ( &HL_inv )[bound_N+1] , Interval ( &descendant )[bound_N] , lazy_segtree& v3 ) // { // int& HL_inv_v = HL_inv[v]; // ll answer = v3.prod( leftmost_descendant[HL_inv_v] , HL_inv_v + 1 ); // list* p_children_v = &( children[v] ); // while( ! p_children_v->empty() ){ // auto itr_v = p_children_v->begin() , end_v = p_children_v->end(); // v = *itr_v; // p_children_v = &( children[v] ); // while( ++itr_v != end_v ){ // answer += sum_v3( *itr_v , children , HL_inv , leftmost_descendant , v3 ); // } // } // return answer; // } // // 解説におけるf(1,v)の表示の第1項の計算 // ll sum_v1( int v , list ( &children )[bound_N+1], int ( &HL_inv )[bound_N+1] , int ( &leftmost_descendant )[bound_N] , lazy_segtree& v1 ) // { // int& HL_inv_v = HL_inv[v]; // // 解説ではvの親に言及しているため暗にv != 1を課しているが、ここではrootの親を便宜上0とすることで場合分けを回避 // ll answer = v1.prod( leftmost_descendant[HL_inv_v] , HL_inv_v + 1 ).third1; // list* p_children_v = &( children[v] ); // while( ! p_children_v->empty() ){ // auto itr_v = p_children_v->begin() , end_v = p_children_v->end(); // v = *itr_v; // p_children_v = &( children[v] ); // while( ++itr_v != end_v ){ // answer += sum_v1( *itr_v , children , HL_inv , leftmost_descendant , v1 ); // } // } // return answer; // } // 解説におけるf(1,v)の計算 inline ll f1v( int v , int ( &parent )[bound_N+1] , int ( &HL_inv )[bound_N+1] , Interval ( &descendant )[bound_N] , lazy_segtree& v1 , lazy_segtree& v3 ) { int& HL_inv_v = HL_inv[v]; Interval& descendant_v = descendant[HL_inv[v]]; ll answer = v1.prod( descendant_v.first , descendant_v.second ).third1; // 解説におけるXの総和は(Ri,Vi)を(1,v)に置き換えてXを定義し直した時の値であることに注意。 // 特に(Ri,Vi)=(v,v)!=(1,1)の時のf(v,v)(v!=1)の計算で呼び出されるf(1,1)の計算で参照されるXは問題文中で定義された集合とは別物であり(Ri,Vi)=(1,1)に置き換えて定義し直したものとなる。 answer -= v3.prod( descendant_v.first , descendant_v.second ); int& parent_v = parent[v]; answer += ( v1.get( HL_inv_v ).third1 / ( v - parent_v ) ) * parent_v; answer /= 2; return answer; } // 解説におけるf(v,v)の計算 inline ll fvv( int v , int ( &parent )[bound_N+1] , int ( &HL_inv )[bound_N+1] , Interval ( &descendant )[bound_N] , list ( &path )[bound_N] , lazy_segtree& v1 , lazy_segtree& v2 , lazy_segtree& v3 ) { ll answer = f1v( 1 , parent , HL_inv , descendant , v1 , v3 ); list& path_v = path[HL_inv[v]]; FOR_ITR( path_v , itr_v , end_v ){ // |S|-c(root,root) = 0であるので本来不要なrootの寄与は自動的に消える answer += v2.prod( itr_v->first , itr_v->second ).fourth2; } return answer; } int main() { UNTIE; CIN_ASSERT( N , 1 , bound_N ); CEXPR( int , bound_Q , 100000 ); CIN_ASSERT( Q , 1 , bound_Q ); // 一旦子と親を全て同じ配列に格納 list children[bound_N+1] = {}; FOR( i , 1 , N ){ CIN_ASSERT( Ai , 1 , N ); CIN_ASSERT( Bi , 1 , N ); assert( Ai != Bi ); children[Ai].push_back( Bi ); children[Bi].push_back( Ai ); } // 子と親の決定 int parent[bound_N+1]; // 解説では各vに対するf(1,v)の表示の第1項の計算畤に各xに対するx-(xの親)を参照しておりx=1の時に未定義参照となるが、 // 等式自体は(xの親)を好きな定数に置き換えても成り立つのでここでは(1の親)を定数で置き換える。 // f(1,v)の表示の第3項を遅延セグメント木から復元する際にv-(vの親)で割る必要があるので、(1の親)を置き換える定数は1以外にする必要がある。 parent[1] = 0; list layer[bound_N] = {}; int children_query[bound_N]; children_query[0] = 1; int start_children_query = 0; int size_children_query = 1; int size_children_query_copy = size_children_query; int depth = 0; while( start_children_query < size_children_query ){ list& layer_curr = layer[depth]; FOR( i , start_children_query , size_children_query ){ int& children_query_i = children_query[i]; layer_curr.push_back( children_query_i ); list& children_i = children[children_query_i]; FOR_ITR( children_i , itr_i , end_i ){ int& j = *itr_i; parent[j] = children_query_i; list& children_ij = children[j]; FOR_ITR( children_ij , itr_ij , end_ij ){ if( children_query_i == *itr_ij ){ children_ij.erase( itr_ij ); break; } } children_query[size_children_query_copy++] = j; } } depth++; start_children_query = size_children_query; size_children_query = size_children_query_copy; } // HL分解のための重さ計算 int weight[bound_N + 1]; FOREQINV( d , depth - 1 , 0 ){ list& layer_curr = layer[d]; FOR_ITR( layer_curr , itr_d , end_d ){ int& i = *itr_d; list& children_curr = children[i]; int& weight_i = weight[i]; weight_i = 1; FOR_ITR( children_curr , itr_i , end_i ){ weight_i += weight[*itr_i]; } } } // HL分解のためのheight計算 int children_H_i; int weight_max; FOREQ( i , 1 , N ){ list& children_i = children[i]; weight_max = -1; FOR_ITR( children_i , itr , end ){ int& j_curr = *itr; int& weight_j_curr = weight[j_curr]; if( weight_max < weight_j_curr ){ weight_max = weight_j_curr; children_H_i = j_curr; } } FOR_ITR( children_i , itr , end ){ if( children_H_i == *itr ){ children_i.erase( itr ); children_i.push_front( children_H_i ); break; } } } // HL分解 // 添え字は0始まり、根に小さい番号づけ。 // この向きでないとH側のpathが区間になるだけで部分木が1つの区間にならず区間族になることに注意。 int HL[bound_N]; int HL_inv[bound_N+1]; list root{ { 1 } }; list::iterator> children_itr_stack{}; children_itr_stack.push_back( root.begin() ); list::iterator> children_end_stack{}; children_end_stack.push_back( root.end() ); int length = 0; while( ! children_itr_stack.empty() ){ list::iterator& itr_curr = children_itr_stack.back(); list::iterator& end_curr = children_end_stack.back(); if( itr_curr == end_curr ){ children_itr_stack.pop_back(); children_end_stack.pop_back(); } else { int& i_curr = *itr_curr; HL_inv[i_curr] = length; HL[length++] = i_curr; list& children_curr = children[i_curr]; children_itr_stack.push_back( children_curr.begin() ); children_end_stack.push_back( children_curr.end() ); itr_curr++; } } // 1からのパスのなすHL上の半開区間[first,second)の計算(ここが各ノードでlogオーダーになることがHL分解特有の事情) list path[bound_N]; path[0] = list( { Interval( 0 , 1 ) } ); FOR( d , 1 , depth ){ list& layer_curr = layer[d]; FOR_ITR( layer_curr , itr_d , end_d ){ int& i = *itr_d; int& parent_i = parent[i]; int& HL_inv_parent_i = HL_inv[parent_i]; int& HL_inv_i = HL_inv[i]; list& path_parent_i = path[HL_inv_parent_i]; list& path_i = path[HL_inv_i]; path_i = path_parent_i; if( children[parent_i].front() == i ){ path_i.back().second = HL_inv_i + 1; } else { path_i.push_back( Interval( HL_inv_i , HL_inv_i + 1 ) ); } } } // ノードの子孫のなすHL上の半開区間[first,second)の計算 Interval descendant[bound_N]; FOREQINV( d , depth - 1 , 0 ){ list& layer_curr = layer[d]; FOR_ITR( layer_curr , itr_d , end_d ){ int& i = *itr_d; list& children_curr = children[i]; int& HL_inv_i = HL_inv[i]; descendant[HL_inv_i] = Interval( HL_inv_i , children_curr.empty() ? HL_inv_i + 1 : descendant[HL_inv[children_curr.back()]].second ); } } // 解説における(x-(xの親),(x-(xの親))c(1,x),(x-(xの親))c(1,x)^2)の管理 lazy_segtree v1{ N }; FOR( i , 0 , N ){ int& HL_i = HL[i]; v1.set( i , S1( S1_12( HL_i - parent[HL_i] , 0 ) , 0 ) ); } // 解説における(x-(xの親),(x-(xの親))c(1,x),(x-(xの親))(|S|-c(1,x)),(x-(xの親))c(1,x)(|S|-c(1,x)))の管理 lazy_segtree v2{ N }; FOR( i , 0 , N ){ int& HL_i = HL[i]; v2.set( i , S2( S2_12( HL_i - parent[HL_i] , 0 ) , S2_34( 0 , 0 ) ) ); } // Xの総和を計算するための(x in S ? x : 0)の管理 lazy_segtree v3{ N }; set S{}; int sign , x , HL_inv_x; bool belong; // クエリ処理 REPEAT( Q ){ CIN_ASSERT( Ui , 1 , N ); CIN_ASSERT( Ri , 1 , N ); CIN_ASSERT( Vi , 1 , N ); if( S.count( Ui ) == 0 ){ sign = 1; S.insert( Ui ); } else { sign = -1; S.erase( Ui ); } int& HL_inv_Ui = HL_inv[Ui]; v3.apply( HL_inv_Ui , sign * Ui ); v2.apply( 0 , N , F2( 0 , sign ) ); list& path_Ui = path[HL_inv[Ui]]; FOR_ITR( path_Ui , itr_i , end_i ){ Interval& path_Uij = *itr_i; v1.apply( path_Uij.first , path_Uij.second , sign ); v2.apply( path_Uij.first , path_Uij.second , F2( sign , -sign ) ); } int& HL_inv_Vi = HL_inv[Vi]; if( Ri == Vi ){ COUT( fvv( Vi , parent , HL_inv , descendant , path , v1 , v2 , v3 ) ); } else { int& HL_inv_Ri = HL_inv[Ri]; belong = false; list& path_Ri = path[HL_inv_Ri]; FOR_ITR( path_Ri , itr_Ri , end_Ri ){ Interval& path_Rij = *itr_Ri; if( path_Rij.first <= HL_inv_Vi && HL_inv_Vi < path_Rij.second ){ belong = true; if( HL_inv_Vi + 1 == path_Rij.second ){ itr_Ri++; HL_inv_x = itr_Ri->first; } else { HL_inv_x = HL_inv_Vi + 1; } x = HL[HL_inv_x]; COUT( fvv( Vi , parent , HL_inv , descendant , path , v1 , v2 , v3 ) - f1v( x , parent , HL_inv , descendant , v1 , v3 ) - ( v2.get( HL_inv_x ).fourth2 / ( x - Vi ) ) * Vi ); break; } } if( ! belong ){ COUT( f1v( Vi , parent , HL_inv , descendant , v1 , v3 )); } } } QUIT; }