#line 1 "verify/graph/tree/tree_algorithms.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"
#include<algorithm>
#include<array>
#include<cassert>
#line 1 "utilities/fast_io.hpp"
#line 6 "utilities/fast_io.hpp"
#include<cerrno>
#include<charconv>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstdint>
#include<cstring>
#include<iterator>
#include<string>
#include<sys/stat.h>
#include<type_traits>
#include<utility>
#include<unistd.h>
#include<vector>namespacem1une{namespaceutilities{structFastOutput;namespaceinternal{// Shared with the convenience helpers in template.hpp.inlineFastOutput*standard_output_instance=nullptr;// Detect std::begin(x), std::end(x).template<classT,class=void>structis_range:std::false_type{};template<classT>structis_range<T,std::void_t<decltype(std::begin(std::declval<T&>())),decltype(std::end(std::declval<T&>()))>>:std::true_type{};template<classT>inlineconstexprboolis_range_v=is_range<T>::value;template<classT>usingrange_reference_t=decltype(*std::begin(std::declval<T&>()));template<classT>usingrange_value_t=std::remove_cv_t<std::remove_reference_t<range_reference_t<T>>>;template<classT,class=void>structrange_stored_value{usingtype=range_value_t<T>;};template<classT>structrange_stored_value<T,std::void_t<typenamestd::remove_cv_t<std::remove_reference_t<T>>::value_type>>{usingtype=typenamestd::remove_cv_t<std::remove_reference_t<T>>::value_type;};template<classT>usingrange_stored_value_t=typenamerange_stored_value<T>::type;// Treat strings and C strings as scalar output objects, not as ranges.template<classT>structis_char_array:std::false_type{};template<classT,std::size_tN>structis_char_array<T[N]>:std::bool_constant<std::is_same_v<std::remove_cv_t<T>,char>>{};template<classT>structis_string_like:std::bool_constant<std::is_same_v<std::decay_t<T>,std::string>||std::is_same_v<std::decay_t<T>,constchar*>||std::is_same_v<std::decay_t<T>,char*>||is_char_array<std::remove_reference_t<T>>::value>{};template<classT>inlineconstexprboolis_string_like_v=is_string_like<T>::value;// ModInt-like type: x.val() is printable, and x can be assigned from long long.template<classT,class=void>structhas_val_method:std::false_type{};template<classT>structhas_val_method<T,std::void_t<decltype(std::declval<constT&>().val())>>:std::true_type{};template<classT>inlineconstexprboolhas_val_method_v=has_val_method<T>::value;template<classT,class=void>structhas_static_mod_raw:std::false_type{};template<classT>structhas_static_mod_raw<T,std::void_t<decltype(T::mod()),decltype(T::raw(std::declval<uint32_t>()))>>:std::true_type{};template<classT>inlineconstexprboolhas_static_mod_raw_v=has_static_mod_raw<T>::value;// libstdc++ before GCC 16 does not classify __int128 as an integral type in// strict ISO modes such as -std=c++23. Keep the fast-I/O interface independent// of that implementation detail.template<classT>inlineconstexprboolis_integral_v=std::is_integral_v<T>||std::is_same_v<std::remove_cv_t<T>,__int128_t>||std::is_same_v<std::remove_cv_t<T>,__uint128_t>;template<classT>inlineconstexprboolis_signed_v=std::is_signed_v<T>||std::is_same_v<std::remove_cv_t<T>,__int128_t>;template<classT>structmake_unsigned{usingtype=std::make_unsigned_t<T>;};template<>structmake_unsigned<__int128_t>{usingtype=__uint128_t;};template<>structmake_unsigned<__uint128_t>{usingtype=__uint128_t;};template<classT>usingmake_unsigned_t=typenamemake_unsigned<std::remove_cv_t<T>>::type;}// namespace internalstructFastInput{staticconstexprintbuffer_size=1<<20;private:std::FILE*_stream;char_buffer[buffer_size];int_position;int_length;int_file_descriptor;bool_streaming;boolrefill(){_position=0;if(_streaming){ssize_tlength;do{length=::read(_file_descriptor,_buffer,buffer_size);}while(length<0&&errno==EINTR);if(length<=0){_length=0;returnfalse;}_length=int(length);}else{_length=int(std::fread(_buffer,1,buffer_size,_stream));}return_length!=0;}template<classT>boolread_integer_from_stream(T&value){if(!skip_spaces())returnfalse;intc=read_char_raw();boolnegative=false;if(c=='-'){negative=true;c=read_char_raw();}ifconstexpr(internal::is_signed_v<T>){Tresult=0;while('0'<=c&&c<='9'){result=negative?result*10-(c-'0'):result*10+(c-'0');c=read_char_raw();}value=result;}else{Tresult=0;while('0'<=c&&c<='9'){result=result*10+T(c-'0');c=read_char_raw();}value=negative?T(0)-result:result;}returntrue;}boolprepare_number(){if(_length-_position>=64)returntrue;constintremaining=_length-_position;if(remaining>0)std::memmove(_buffer,_buffer+_position,remaining);constintadded=int(std::fread(_buffer+remaining,1,buffer_size-remaining,_stream));_position=0;_length=remaining+added;if(_length<buffer_size)_buffer[_length]='\0';return_length!=0;}public:explicitFastInput(std::FILE*stream=stdin):_stream(stream),_position(0),_length(0),_file_descriptor(::fileno(stream)),_streaming([&]{structstatstatus;return_file_descriptor>=0&&::fstat(_file_descriptor,&status)==0&&!S_ISREG(status.st_mode);}()){}FastInput(constFastInput&)=delete;FastInput&operator=(constFastInput&)=delete;intread_char_raw(){if(_position==_length&&!refill())returnEOF;return_buffer[_position++];}boolskip_spaces(){intc=read_char_raw();while(c!=EOF&&c<=' ')c=read_char_raw();if(c==EOF)returnfalse;--_position;returntrue;}boolread(char&value){if(!skip_spaces())returnfalse;value=char(read_char_raw());returntrue;}boolread(std::string&value){if(!skip_spaces())returnfalse;value.clear();while(true){constintbegin=_position;while(_position<_length&&static_cast<unsignedchar>(_buffer[_position])>' '){++_position;}value.append(_buffer+begin,_position-begin);if(_position<_length){++_position;returntrue;}if(!refill())returntrue;}}boolread(bool&value){intx;if(!read(x))returnfalse;value=x!=0;returntrue;}template<classT>std::enable_if_t<internal::is_integral_v<T>&&!std::is_same_v<std::remove_cv_t<T>,bool>&&!std::is_same_v<std::remove_cv_t<T>,char>,bool>read(T&value){if(_streaming)returnread_integer_from_stream(value);if(!prepare_number())returnfalse;intc=static_cast<unsignedchar>(_buffer[_position++]);while(c<=' ')c=static_cast<unsignedchar>(_buffer[_position++]);boolnegative=false;if(c=='-'){negative=true;c=static_cast<unsignedchar>(_buffer[_position++]);}ifconstexpr(internal::is_signed_v<T>){Tresult=0;while('0'<=c&&c<='9'){constintfirst=c-'0';constintsecond=static_cast<unsignedchar>(_buffer[_position])-'0';if(0<=second&&second<=9){result=negative?result*100-(first*10+second):result*100+(first*10+second);++_position;}else{result=negative?result*10-first:result*10+first;}c=static_cast<unsignedchar>(_buffer[_position++]);}value=result;}else{Tresult=0;while('0'<=c&&c<='9'){constunsignedfirst=unsigned(c-'0');constintsecond=static_cast<unsignedchar>(_buffer[_position])-'0';if(0<=second&&second<=9){result=result*100+T(first*10+unsigned(second));++_position;}else{result=result*10+T(first);}c=static_cast<unsignedchar>(_buffer[_position++]);}value=negative?T(0)-result:result;}if(_position>_length)_position=_length;returntrue;}template<classT>std::enable_if_t<std::is_floating_point_v<T>,bool>read(T&value){if(!skip_spaces())returnfalse;intc=read_char_raw();boolnegative=false;if(c=='-'||c=='+'){negative=c=='-';c=read_char_raw();}longdoubleresult=0;while('0'<=c&&c<='9'){result=result*10+(c-'0');c=read_char_raw();}if(c=='.'){longdoubleplace=0.1L;c=read_char_raw();while('0'<=c&&c<='9'){result+=(c-'0')*place;place*=0.1L;c=read_char_raw();}}if(c=='e'||c=='E'){c=read_char_raw();boolexponent_negative=false;if(c=='-'||c=='+'){exponent_negative=c=='-';c=read_char_raw();}intexponent=0;while('0'<=c&&c<='9'){exponent=exponent*10+(c-'0');c=read_char_raw();}longdoublescale=1;longdoublepower=10;while(exponent>0){if(exponent&1)scale*=power;power*=power;exponent>>=1;}result=exponent_negative?result/scale:result*scale;}value=static_cast<T>(negative?-result:result);returntrue;}template<classT>std::enable_if_t<internal::has_val_method_v<T>&&!internal::is_integral_v<T>&&!internal::is_range_v<T>,bool>read(T&value){longlongx;if(!read(x))returnfalse;ifconstexpr(internal::has_static_mod_raw_v<T>){if(x>=0&&uint64_t(x)<uint64_t(T::mod())){value=T::raw(uint32_t(x));}else{value=T(x);}}else{value=T(x);}returntrue;}template<classFirst,classSecond>boolread(std::pair<First,Second>&value){if(!read(value.first))returnfalse;returnread(value.second);}template<classRange>std::enable_if_t<internal::is_range_v<Range>&&!internal::is_string_like_v<Range>,bool>read(Range&range){usingStoredValue=internal::range_stored_value_t<Range>;constexprboolnested=internal::is_range_v<StoredValue>&&!internal::is_string_like_v<StoredValue>;for(auto&&value:range){ifconstexpr(std::is_same_v<StoredValue,bool>&&!nested){boolx;if(!read(x))returnfalse;value=x;}else{if(!read(value))returnfalse;}}returntrue;}template<classFirst,classSecond,class...Rest>boolread(First&first,Second&second,Rest&...rest){if(!read(first))returnfalse;returnread(second,rest...);}template<classT>FastInput&operator>>(T&value){if(!read(value))std::abort();return*this;}};structFastOutput{staticconstexprintbuffer_size=1<<20;private:inlinestaticconstautodigit_quads=[]{std::array<char,40000>result{};for(inti=0;i<10000;i++){intvalue=i;for(intj=3;j>=0;j--){result[4*i+j]=char('0'+value%10);value/=10;}}returnresult;}();std::FILE*_stream;char_buffer[buffer_size];int_position;int_precision;std::chars_format_float_format;char_range_separator;std::string*_capture=nullptr;template<classT>std::stringformat_cell(constT&value){std::stringresult;structCaptureGuard{std::string*⌖std::string*previous;~CaptureGuard(){target=previous;}}guard{_capture,_capture};_capture=&result;write(value);returnresult;}template<classMatrix>voidwrite_aligned_matrix(constMatrix&matrix){std::vector<std::vector<std::string>>rows;std::vector<std::size_t>widths;for(constauto&row:matrix){auto&cells=rows.emplace_back();std::size_tcolumn=0;for(constauto&value:row){cells.push_back(format_cell(value));if(column==widths.size())widths.push_back(0);widths[column]=std::max(widths[column],cells.back().size());++column;}}boolfirst=true;for(constauto&row:rows){if(!first)write_char('\n');first=false;for(std::size_tcolumn=0;column<row.size();++column){if(column!=0)write_char(_range_separator);for(std::size_tpadding=row[column].size();padding<widths[column];++padding){write_char(' ');}write(row[column]);}}}public:explicitFastOutput(std::FILE*stream=stdout):_stream(stream),_position(0),_precision(6),_float_format(std::chars_format::general),_range_separator(' '){if(_stream==stdout&&internal::standard_output_instance==nullptr){internal::standard_output_instance=this;}}FastOutput(constFastOutput&)=delete;FastOutput&operator=(constFastOutput&)=delete;~FastOutput(){flush();if(internal::standard_output_instance==this){internal::standard_output_instance=nullptr;}}voidflush(){if(_position!=0){std::fwrite(_buffer,1,_position,_stream);_position=0;}std::fflush(_stream);}voidwrite_char(charc){if(_capture!=nullptr){_capture->push_back(c);return;}if(_position==buffer_size)flush();_buffer[_position++]=c;}voidwrite(constchar*s){while(*s!='\0')write_char(*s++);}voidwrite(conststd::string&s){if(_capture!=nullptr){_capture->append(s);return;}std::size_tposition=0;while(position<s.size()){if(_position==buffer_size)flush();conststd::size_tcopied=std::min<std::size_t>(buffer_size-_position,s.size()-position);std::memcpy(_buffer+_position,s.data()+position,copied);_position+=int(copied);position+=copied;}}voidwrite(charc){write_char(c);}voidwrite(boolvalue){write_char(value?'1':'0');}template<classT>std::enable_if_t<std::is_floating_point_v<T>>write(Tvalue){chardigits[128];auto[end,error]=std::to_chars(digits,digits+sizeof(digits),value,_float_format,_precision);if(error!=std::errc())std::abort();for(constchar*pointer=digits;pointer!=end;pointer++){write_char(*pointer);}}template<classT>std::enable_if_t<internal::is_integral_v<T>&&!std::is_same_v<std::remove_cv_t<T>,bool>&&!std::is_same_v<std::remove_cv_t<T>,char>>write(Tvalue){usingRaw=std::remove_cv_t<T>;usingUnsigned=internal::make_unsigned_t<Raw>;Unsignedmagnitude;ifconstexpr(internal::is_signed_v<Raw>){if(value<0){write_char('-');magnitude=Unsigned(0)-Unsigned(value);}else{magnitude=Unsigned(value);}}else{magnitude=value;}if(magnitude==0){write_char('0');return;}unsignedchunks[16];intcount=0;while(magnitude>=10000){constUnsignedquotient=magnitude/10000;chunks[count++]=unsigned(magnitude-quotient*10000);magnitude=quotient;}if(_capture==nullptr&&_position>buffer_size-64)flush();charcaptured[64];char*constbegin=_capture!=nullptr?captured:_buffer+_position;char*destination=begin;constunsignedleading=unsigned(magnitude);constchar*first=digit_quads.data()+4*leading;intskip=leading<10?3:leading<100?2:leading<1000?1:0;for(;skip<4;skip++)*destination++=first[skip];while(count--){constchar*digits=digit_quads.data()+4*chunks[count];std::memcpy(destination,digits,4);destination+=4;}if(_capture!=nullptr){_capture->append(begin,destination-begin);}else{_position+=int(destination-begin);}}template<classT>std::enable_if_t<internal::has_val_method_v<T>&&!internal::is_integral_v<T>&&!internal::is_range_v<T>>write(constT&value){write(value.val());}template<classFirst,classSecond>voidwrite(conststd::pair<First,Second>&value){write(value.first);write_char(' ');write(value.second);}template<classRange>std::enable_if_t<internal::is_range_v<Range>&&!internal::is_string_like_v<Range>>write(constRange&range){usingStoredValue=internal::range_stored_value_t<constRange>;constexprboolnested=internal::is_range_v<StoredValue>&&!internal::is_string_like_v<StoredValue>;boolfirst=true;for(constauto&value:range){if(!first)write_char(nested?'\n':_range_separator);first=false;ifconstexpr(std::is_same_v<StoredValue,bool>&&!nested){write(static_cast<bool>(value));}else{write(value);}}}template<classFirst,class...Rest>voidprint(constFirst&first,constRest&...rest){write(first);((write_char(' '),write(rest)),...);}voidprintln(){write_char('\n');}voidset_precision(intprecision){_precision=precision;}voidset_fixed(intprecision=6){_float_format=std::chars_format::fixed;_precision=precision;}voidset_general(intprecision=6){_float_format=std::chars_format::general;_precision=precision;}voidset_range_separator(charseparator){_range_separator=separator;}template<classMatrix>voidwrite_aligned(constMatrix&matrix){usingRow=internal::range_stored_value_t<constMatrix>;usingCell=internal::range_stored_value_t<constRow>;static_assert(internal::is_range_v<Row>&&!internal::is_string_like_v<Row>,"write_aligned requires a two-dimensional range");static_assert(!internal::is_range_v<Cell>||internal::is_string_like_v<Cell>,"write_aligned requires scalar cells");write_aligned_matrix(matrix);}template<classMatrix>voidprintln_aligned(constMatrix&matrix){write_aligned(matrix);write_char('\n');}template<class...Args>voidprintln(constArgs&...args){print(args...);write_char('\n');}template<classT>FastOutput&operator<<(constT&value){write(value);return*this;}};}// namespace utilities}// namespace m1une#line 7 "verify/graph/tree/tree_algorithms.test.cpp"
#include<numeric>
#include<random>
#include<set>
#line 11 "verify/graph/tree/tree_algorithms.test.cpp"
#line 1 "graph/graph.hpp"
#line 8 "graph/graph.hpp"
namespacem1une{namespacegraph{template<classT=int>structEdge{usingcost_type=T;intfrom;intto;Tcost;intid;boolalive;Edge():from(-1),to(-1),cost(T()),id(-1),alive(true){}Edge(intfrom_,intto_,Tcost_=T(1),intid_=-1,boolalive_=true):from(from_),to(to_),cost(cost_),id(id_),alive(alive_){}intother(intv)const{assert(v==from||v==to);returnfrom^to^v;}};template<classT=int>structGraph{usingedge_type=Edge<T>;usingcost_type=T;private:structEdgePositions{std::array<std::pair<int,int>,2>value{};intsize=0;voidpush_back(std::pair<int,int>position){assert(size<2);value[size++]=position;}};int_n;int_edge_count;std::vector<std::vector<edge_type>>_g;std::vector<EdgePositions>_edge_positions;public:Graph():_n(0),_edge_count(0){}explicitGraph(intn):_n(n),_edge_count(0),_g(n){assert(0<=n);}intsize()const{return_n;}boolempty()const{return_n==0;}intedge_count()const{return_edge_count;}intadd_vertex(){_g.emplace_back();return_n++;}intadd_directed_edge(intfrom,intto,Tcost=T(1)){assert(0<=from&&from<_n);assert(0<=to&&to<_n);intid=_edge_count++;intidx=int(_g[from].size());_g[from].push_back(edge_type(from,to,cost,id));_edge_positions.emplace_back();_edge_positions.back().push_back({from,idx});returnid;}intadd_edge(intu,intv,Tcost=T(1)){assert(0<=u&&u<_n);assert(0<=v&&v<_n);intid=_edge_count++;intu_idx=int(_g[u].size());_g[u].push_back(edge_type(u,v,cost,id));intv_idx=int(_g[v].size());_g[v].push_back(edge_type(v,u,cost,id));_edge_positions.emplace_back();_edge_positions.back().push_back({u,u_idx});_edge_positions.back().push_back({v,v_idx});returnid;}voidset_edge_alive(intid,boolalive){assert(0<=id&&id<_edge_count);for(inti=0;i<_edge_positions[id].size;++i){auto[v,idx]=_edge_positions[id].value[i];_g[v][idx].alive=alive;}}voiderase_edge(intid){set_edge_alive(id,false);}voidrevive_edge(intid){set_edge_alive(id,true);}boolis_edge_alive(intid)const{assert(0<=id&&id<_edge_count);assert(_edge_positions[id].size!=0);auto[v,idx]=_edge_positions[id].value[0];return_g[v][idx].alive;}conststd::vector<edge_type>&operator[](intv)const{assert(0<=v&&v<_n);return_g[v];}std::vector<edge_type>&operator[](intv){assert(0<=v&&v<_n);return_g[v];}conststd::vector<std::vector<edge_type>>&adjacency()const{return_g;}std::vector<std::vector<edge_type>>&adjacency(){return_g;}std::vector<edge_type>edges(boolinclude_inactive=false)const{std::vector<edge_type>result;result.reserve(_edge_count);std::vector<char>used(_edge_count,false);for(intv=0;v<_n;v++){for(constauto&e:_g[v]){if(!include_inactive&&!e.alive)continue;if(0<=e.id&&e.id<_edge_count){if(used[e.id])continue;used[e.id]=true;}result.push_back(e);}}returnresult;}Graphreversed()const{Graphresult(_n);result._edge_count=_edge_count;result._edge_positions.assign(_edge_count,{});for(intv=0;v<_n;v++){for(constauto&e:_g[v]){intidx=int(result._g[e.to].size());result._g[e.to].push_back(edge_type(e.to,e.from,e.cost,e.id,e.alive));if(0<=e.id&&e.id<_edge_count)result._edge_positions[e.id].push_back({e.to,idx});}}returnresult;}};}// namespace graph}// namespace m1une#line 1 "graph/tree/all.hpp"
#line 1 "graph/tree/cartesian_tree.hpp"
#line 6 "graph/tree/cartesian_tree.hpp"
#include<functional>
#include<limits>
#line 10 "graph/tree/cartesian_tree.hpp"
#line 12 "graph/tree/cartesian_tree.hpp"
namespacem1une{namespacetree{structCartesianTree{introot;std::vector<int>parent;std::vector<int>left;std::vector<int>right;private:int_n;voidcheck_vertex(intv)const{assert(0<=v&&v<_n);}public:CartesianTree():root(-1),_n(0){}template<classT,classCompare=std::less<T>>explicitCartesianTree(conststd::vector<T>&a,Comparecomp=Compare()):root(-1),_n(0){build(a,comp);}template<classT,classCompare=std::less<T>>voidbuild(conststd::vector<T>&a,Comparecomp=Compare()){assert(a.size()<=static_cast<std::size_t>(std::numeric_limits<int>::max()));_n=int(a.size());root=-1;parent.assign(_n,-1);left.assign(_n,-1);right.assign(_n,-1);std::vector<int>stack;stack.reserve(_n);for(inti=0;i<_n;i++){intlast=-1;while(!stack.empty()&&comp(a[i],a[stack.back()])){last=stack.back();stack.pop_back();}if(last!=-1){left[i]=last;parent[last]=i;}if(!stack.empty()){right[stack.back()]=i;parent[i]=stack.back();}stack.push_back(i);}if(!stack.empty())root=stack.front();}intsize()const{return_n;}boolempty()const{return_n==0;}intparent_or_self(intv)const{check_vertex(v);returnparent[v]==-1?v:parent[v];}std::vector<int>parent_with_root_self()const{std::vector<int>result=parent;if(root!=-1)result[root]=root;returnresult;}std::vector<std::pair<int,int>>edges()const{std::vector<std::pair<int,int>>result;if(_n==0)returnresult;result.reserve(_n-1);for(intv=0;v<_n;v++){if(parent[v]!=-1)result.emplace_back(parent[v],v);}returnresult;}m1une::graph::Graph<int>to_graph()const{m1une::graph::Graph<int>g(_n);for(intv=0;v<_n;v++){if(parent[v]!=-1)g.add_edge(parent[v],v);}returng;}};template<classT,classCompare=std::less<T>>CartesianTreecartesian_tree(conststd::vector<T>&a,Comparecomp=Compare()){CartesianTreeresult;result.build(a,comp);returnresult;}}// namespace tree}// namespace m1une#line 1 "graph/tree/centroid_decomposition.hpp"
#line 6 "graph/tree/centroid_decomposition.hpp"
#line 8 "graph/tree/centroid_decomposition.hpp"
namespacem1une{namespacetree{template<classT=int>structCentroidDecomposition{intn;std::vector<int>parent;std::vector<int>depth;std::vector<int>order;std::vector<int>roots;std::vector<std::vector<int>>children;private:std::vector<int>_subtree_size;std::vector<int>_work_parent;std::vector<char>_removed;voidbuild_component(constm1une::graph::Graph<T>&g,intstart,intp,intd){std::vector<int>nodes;std::vector<int>stack={start};_work_parent[start]=-2;while(!stack.empty()){intv=stack.back();stack.pop_back();nodes.push_back(v);for(constauto&e:g[v]){if(!e.alive||_removed[e.to])continue;if(_work_parent[e.to]!=-1)continue;_work_parent[e.to]=v;stack.push_back(e.to);}}for(intv:nodes)_subtree_size[v]=1;for(inti=int(nodes.size())-1;i>=0;i--){intv=nodes[i];if(_work_parent[v]>=0)_subtree_size[_work_parent[v]]+=_subtree_size[v];}inttotal=int(nodes.size());intcentroid=start;intbest=total+1;for(intv:nodes){intlargest=total-_subtree_size[v];for(constauto&e:g[v]){if(!e.alive||_removed[e.to])continue;if(_work_parent[e.to]==v)largest=std::max(largest,_subtree_size[e.to]);}if(largest<best){best=largest;centroid=v;}}for(intv:nodes)_work_parent[v]=-1;parent[centroid]=p;depth[centroid]=d;order.push_back(centroid);if(p==-1){roots.push_back(centroid);}else{children[p].push_back(centroid);}_removed[centroid]=true;for(constauto&e:g[centroid]){if(!e.alive||_removed[e.to])continue;build_component(g,e.to,centroid,d+1);}}public:CentroidDecomposition():n(0){}explicitCentroidDecomposition(constm1une::graph::Graph<T>&g){build(g);}voidbuild(constm1une::graph::Graph<T>&g){n=g.size();parent.assign(n,-1);depth.assign(n,-1);order.clear();order.reserve(n);roots.clear();children.assign(n,{});_subtree_size.assign(n,0);_work_parent.assign(n,-1);_removed.assign(n,false);for(intv=0;v<n;v++){if(depth[v]==-1)build_component(g,v,-1,0);}}intsize()const{returnn;}boolempty()const{returnn==0;}introot()const{returnroots.empty()?-1:roots[0];}};}// namespace tree}// namespace m1une#line 1 "graph/tree/cumulative_sum.hpp"
#line 8 "graph/tree/cumulative_sum.hpp"
#line 1 "monoid/add.hpp"
namespacem1une{namespacemonoid{// Monoid for addition (Range Sum).template<typenameT>structAdd{usingvalue_type=T;staticconstexprboolcommutative=true;// Returns the identity element for addition, which is 0.staticconstexprTid(){returnT(0);}// Returns the sum of a and b.staticconstexprTop(constT&a,constT&b){returna+b;}staticconstexprTinv(constT&x){return-x;}};}// namespace monoid}// namespace m1une#line 1 "monoid/concept.hpp"
#include<concepts>namespacem1une{namespacemonoid{// Concept to check if a type satisfies the requirements of a Monoid.// A Monoid must have a `value_type`, an identity element `id()`, and an associative binary operation `op()`.template<typenameM>conceptIsMonoid=requires(typenameM::value_typea,typenameM::value_typeb){// 1. Must define `value_type`typenameM::value_type;// 2. Must have a static method `id()` returning `value_type`{M::id()}->std::same_as<typenameM::value_type>;// 3. Must have a static method `op(a, b)` returning `value_type`{M::op(a,b)}->std::same_as<typenameM::value_type>;};// Concept for groups. A type satisfying this concept must also obey the group// laws; concepts can check the interface but not the algebraic properties.template<typenameM>conceptIsGroup=IsMonoid<M>&&requires(typenameM::value_typea){{M::inv(a)}->std::same_as<typenameM::value_type>;};// Concept for commutative groups. Commutativity is a semantic requirement and// cannot be checked by a C++ concept.template<typenameM>conceptIsCommutativeGroup=IsGroup<M>;}// namespace monoid}// namespace m1une#line 12 "graph/tree/cumulative_sum.hpp"
namespacem1une{namespacetree{// Static cumulative products on root paths. Values are attached to vertices by// default; set EdgeValues to true to index them by graph edge id instead.template<m1une::monoid::IsCommutativeGroupGroup,boolEdgeValues=false>classTreeCumulativeProduct{public:usingvalue_type=typenameGroup::value_type;private:int_n=0;int_root=-1;std::vector<int>_parent;std::vector<int>_depth;std::vector<int>_head;std::vector<value_type>_prefix;voidcheck_vertex(intvertex)const{assert(0<=vertex&&vertex<_n);}public:TreeCumulativeProduct()=default;template<classEdgeCost>explicitTreeCumulativeProduct(constm1une::graph::Graph<EdgeCost>&graph,conststd::vector<value_type>&values,introot=0){build(graph,values,root);}template<classEdgeCost>voidbuild(constm1une::graph::Graph<EdgeCost>&graph,conststd::vector<value_type>&values,introot=0){_n=graph.size();_root=_n==0?-1:root;assert(int(values.size())==(EdgeValues?graph.edge_count():graph.size()));_parent.assign(_n,-2);_depth.assign(_n,0);_head.assign(_n,-1);_prefix.assign(_n,Group::id());if(_n==0)return;assert(0<=root&&root<_n);std::vector<int>parent_edge(_n,-1);std::vector<int>order;order.reserve(_n);std::vector<int>stack={root};_parent[root]=-1;while(!stack.empty()){intvertex=stack.back();stack.pop_back();order.push_back(vertex);for(constauto&edge:graph[vertex]){if(!edge.alive||_parent[edge.to]!=-2)continue;_parent[edge.to]=vertex;parent_edge[edge.to]=edge.id;_depth[edge.to]=_depth[vertex]+1;stack.push_back(edge.to);}}assert(int(order.size())==_n);std::vector<int>subtree_size(_n,1);std::vector<int>heavy(_n,-1);for(intindex=_n-1;index>0;index--){intvertex=order[index];intparent=_parent[vertex];subtree_size[parent]+=subtree_size[vertex];if(heavy[parent]==-1||subtree_size[heavy[parent]]<subtree_size[vertex]){heavy[parent]=vertex;}}std::vector<std::pair<int,int>>starts;starts.emplace_back(root,root);while(!starts.empty()){auto[start,head]=starts.back();starts.pop_back();for(intvertex=start;vertex!=-1;vertex=heavy[vertex]){_head[vertex]=head;for(constauto&edge:graph[vertex]){if(edge.alive&&_parent[edge.to]==vertex&&edge.to!=heavy[vertex]){starts.emplace_back(edge.to,edge.to);}}}}ifconstexpr(!EdgeValues)_prefix[root]=values[root];for(intvertex:order){if(vertex==root)continue;ifconstexpr(EdgeValues){assert(0<=parent_edge[vertex]);_prefix[vertex]=Group::op(_prefix[_parent[vertex]],values[parent_edge[vertex]]);}else{_prefix[vertex]=Group::op(_prefix[_parent[vertex]],values[vertex]);}}}intsize()const{return_n;}boolempty()const{return_n==0;}introot()const{return_root;}intlca(intfirst,intsecond)const{check_vertex(first);check_vertex(second);while(_head[first]!=_head[second]){if(_depth[_head[first]]<_depth[_head[second]]){std::swap(first,second);}first=_parent[_head[first]];}return_depth[first]<_depth[second]?first:second;}// Product on the root-to-vertex path. The root vertex is included for// vertex values; no edge lies above it in edge-value mode.value_typeprod(intvertex)const{check_vertex(vertex);return_prefix[vertex];}// Product on the simple path from first to second. Both endpoints are// included for vertex values.value_typeprod(intfirst,intsecond)const{intancestor=lca(first,second);value_typeresult=Group::op(_prefix[first],_prefix[second]);result=Group::op(result,Group::inv(_prefix[ancestor]));ifconstexpr(EdgeValues){result=Group::op(result,Group::inv(_prefix[ancestor]));}elseif(_parent[ancestor]!=-1){result=Group::op(result,Group::inv(_prefix[_parent[ancestor]]));}returnresult;}};template<m1une::monoid::IsCommutativeGroupGroup>usingTreeEdgeCumulativeProduct=TreeCumulativeProduct<Group,true>;template<classT,boolEdgeValues=false>classTreeCumulativeSum:publicTreeCumulativeProduct<m1une::monoid::Add<T>,EdgeValues>{private:usingBase=TreeCumulativeProduct<m1une::monoid::Add<T>,EdgeValues>;public:usingBase::Base;Tsum(intvertex)const{returnBase::prod(vertex);}Tsum(intfirst,intsecond)const{returnBase::prod(first,second);}};template<classT>usingTreeEdgeCumulativeSum=TreeCumulativeSum<T,true>;}// namespace tree}// namespace m1une#line 1 "graph/tree/diameter.hpp"
#line 6 "graph/tree/diameter.hpp"
#line 8 "graph/tree/diameter.hpp"
namespacem1une{namespacetree{template<classT=int>structTreeDiameter{Tcost;intedge_count;intfrom;intto;std::vector<int>vertices;std::vector<int>edge_ids;boolempty()const{returnvertices.empty();}};namespaceinternal{template<classT>structFarthestResult{intvertex;std::vector<char>seen;std::vector<T>dist;std::vector<int>parent;std::vector<int>parent_edge;};template<classT>FarthestResult<T>farthest_from(constm1une::graph::Graph<T>&g,intstart){intn=g.size();FarthestResult<T>result;result.vertex=start;result.seen.assign(n,false);result.dist.assign(n,T(0));result.parent.assign(n,-1);result.parent_edge.assign(n,-1);std::vector<int>stack={start};result.seen[start]=true;while(!stack.empty()){intv=stack.back();stack.pop_back();if(result.dist[result.vertex]<result.dist[v])result.vertex=v;for(constauto&e:g[v]){if(!e.alive)continue;if(result.seen[e.to])continue;result.seen[e.to]=true;result.dist[e.to]=result.dist[v]+e.cost;result.parent[e.to]=v;result.parent_edge[e.to]=e.id;stack.push_back(e.to);}}returnresult;}}// namespace internaltemplate<classT>TreeDiameter<T>tree_diameter(constm1une::graph::Graph<T>&g){intn=g.size();TreeDiameter<T>best;best.cost=T(0);best.edge_count=0;best.from=-1;best.to=-1;if(n==0)returnbest;std::vector<char>done(n,false);for(intstart=0;start<n;start++){if(done[start])continue;autofirst=internal::farthest_from(g,start);for(intv=0;v<n;v++){if(first.seen[v])done[v]=true;}autosecond=internal::farthest_from(g,first.vertex);inta=first.vertex;intb=second.vertex;Tcost=second.dist[b];if(best.from!=-1&&!(best.cost<cost))continue;best.cost=cost;best.from=a;best.to=b;best.vertices.clear();best.edge_ids.clear();for(intv=b;v!=-1;v=second.parent[v]){best.vertices.push_back(v);if(v!=a)best.edge_ids.push_back(second.parent_edge[v]);}std::reverse(best.vertices.begin(),best.vertices.end());std::reverse(best.edge_ids.begin(),best.edge_ids.end());best.edge_count=int(best.edge_ids.size());}returnbest;}}// namespace tree}// namespace m1une#line 1 "graph/tree/distance_frequency.hpp"
#line 10 "graph/tree/distance_frequency.hpp"
#line 1 "math/fps/convolution.hpp"
#line 9 "math/fps/convolution.hpp"
#include<new>
#line 13 "math/fps/convolution.hpp"
#if defined(__GNUC__) && !defined(__clang__) && \
(defined(__x86_64__) || defined(__i386__)) && \
!defined(M1UNE_FPS_DISABLE_X86_SIMD)
#include<immintrin.h>
#define M1UNE_FPS_HAS_X86_SIMD 1
#pragma GCC push_options
#pragma GCC target("avx2,bmi")
#endif
#line 1 "math/fps/internal/ntt998_faster.hpp"
#ifdef M1UNE_FPS_HAS_X86_SIMD
#line 9 "math/fps/internal/ntt998_faster.hpp"
#include<immintrin.h>namespacem1une{namespacefps{namespaceinternal{namespacefast998_v2{// Fixed-modulus AVX2 transform with an in-register degree-8 residue product.usingu32=unsigned;usingu64=unsignedlonglong;usingidt=std::size_t;usingI256=__m256i;inlinevoidstore256(void*p,I256x){_mm256_store_si256((I256*)p,x);}inlineI256load256(constvoid*p){return_mm256_load_si256((constI256*)p);}constexpru32shrk(u32x,u32M){returnstd::min(x,x-M);}constexpru32dilt(u32x,u32M){returnstd::min(x,x+M);}constexpru32reduce(u64x,u32niv,u32M){return(x+u64(u32(x)*niv)*M)>>32;}constexpru32mul(u32x,u32y,u32niv,u32M){returnreduce(u64(x)*y,niv,M);}constexpru32mul_s(u32x,u32y,u32niv,u32M){returnshrk(reduce(u64(x)*y,niv,M),M);}constexpru32qpw(u32a,u32b,u32niv,u32M,u32r){for(;b;b>>=1,a=mul(a,a,niv,M)){if(b&1){r=mul(r,a,niv,M);}}returnr;}constexpru32qpw_s(u32a,u32b,u32niv,u32M,u32r){returnshrk(qpw(a,b,niv,M,r),M);}inlineI256shrk32(I256x,I256M){return_mm256_min_epu32(x,_mm256_sub_epi32(x,M));}inlineI256dilt32(I256x,I256M){return_mm256_min_epu32(x,_mm256_add_epi32(x,M));}inlineI256Ladd32(I256x,I256y,I256){return_mm256_add_epi32(x,y);}inlineI256Lsub32(I256x,I256y,I256M){return_mm256_add_epi32(_mm256_sub_epi32(x,y),M);}inlineI256add32(I256x,I256y,I256M){returnshrk32(_mm256_add_epi32(x,y),M);}inlineI256sub32(I256x,I256y,I256M){returndilt32(_mm256_sub_epi32(x,y),M);}template<intmsk>inlineI256neg32_m(I256x,I256M){return_mm256_blend_epi32(x,_mm256_sub_epi32(M,x),msk);}inlineI256reduce(I256a,I256b,I256niv,I256M){I256c=_mm256_mul_epu32(a,niv),d=_mm256_mul_epu32(b,niv);c=_mm256_mul_epu32(c,M),d=_mm256_mul_epu32(d,M);return_mm256_blend_epi32(_mm256_srli_epi64(_mm256_add_epi64(a,c),32),_mm256_add_epi64(b,d),0xaa);}inlineI256mul(I256a,I256b,I256niv,I256M){returnreduce(_mm256_mul_epu32(a,b),_mm256_mul_epu32(_mm256_srli_epi64(a,32),_mm256_srli_epi64(b,32)),niv,M);}inlineI256mul_s(I256a,I256b,I256niv,I256M){returnshrk32(mul(a,b,niv,M),M);}inlineI256mul_bsm(I256a,I256b,I256niv,I256M){returnreduce(_mm256_mul_epu32(a,b),_mm256_mul_epu32(_mm256_srli_epi64(a,32),b),niv,M);}inlineI256mul_bsmfxd(I256a,I256b,I256bniv,I256M){I256cc=_mm256_mul_epu32(a,bniv),dd=_mm256_mul_epu32(_mm256_srli_epi64(a,32),bniv);I256c=_mm256_mul_epu32(a,b),d=_mm256_mul_epu32(_mm256_srli_epi64(a,32),b);cc=_mm256_mul_epu32(cc,M),dd=_mm256_mul_epu32(dd,M);return_mm256_blend_epi32(_mm256_srli_epi64(_mm256_add_epi64(c,cc),32),_mm256_add_epi64(d,dd),0xaa);}inlineI256mul_bfxd(I256a,I256b,I256bniv,I256M){I256cc=_mm256_mul_epu32(a,bniv),dd=_mm256_mul_epu32(_mm256_srli_epi64(a,32),_mm256_srli_epi64(bniv,32));I256c=_mm256_mul_epu32(a,b),d=_mm256_mul_epu32(_mm256_srli_epi64(a,32),_mm256_srli_epi64(b,32));cc=_mm256_mul_epu32(cc,M),dd=_mm256_mul_epu32(dd,M);return_mm256_blend_epi32(_mm256_srli_epi64(_mm256_add_epi64(c,cc),32),_mm256_add_epi64(d,dd),0xaa);}inlineI256mul_upd_rt(I256a,I256bu,I256M){I256cc=_mm256_mul_epu32(a,bu),c=_mm256_mul_epu32(a,_mm256_srli_epi64(bu,32));cc=_mm256_mul_epu32(cc,M);returnshrk32(_mm256_srli_epi64(_mm256_add_epi64(c,cc),32),M);}constexprauto_mxlg=26,_lg_itth=6;constexprauto_itth=idt(1)<<_lg_itth;static_assert(_lg_itth%2==0);structFNTT32_info{u32mod,mod2,niv,one,r2,r3,img,imgniv,RT1[_mxlg];alignas(32)std::array<u32,8>rt3[_mxlg-2],rt3i[_mxlg-2],bwbr,bwb,bwbi,rt4[_mxlg-3],rt4niv[_mxlg-3],rt4i[_mxlg-3],rt4iniv[_mxlg-3],pr2,pr4,pr2niv,pr4niv,pr2i,pr2iniv,pr4i,pr4iniv;constexprFNTT32_info(constu32m):mod(m),mod2(m*2),niv([&]{u32n=2+m;for(inti=0;i<4;++i){n*=2+m*n;}returnn;}()),one((-m)%m),r2((-u64(m))%m),r3(mul_s(r2,r2,niv,m)),img{},imgniv{},RT1{},rt3{},rt3i{},bwbr{},bwb{},bwbi{},rt4{},rt4niv{},rt4i{},rt4iniv{},pr2{},pr4{},pr2niv{},pr4niv{},pr2i{},pr2iniv{},pr4i{},pr4iniv{}{constintk=__builtin_ctz(m-1);u32_g=mul(3,r2,niv,mod);for(;;++_g){if(qpw_s(_g,mod>>1,niv,mod,one)!=one){break;}}_g=qpw(_g,mod>>k,niv,mod,one);u32rt1[_mxlg-1],rt1i[_mxlg-1];rt1[k-2]=_g,rt1i[k-2]=qpw(_g,mod-2,niv,mod,one);for(inti=k-2;i>0;--i){rt1[i-1]=mul(rt1[i],rt1[i],niv,mod);rt1i[i-1]=mul(rt1i[i],rt1i[i],niv,mod);}RT1[k-1]=qpw_s(_g,3,niv,mod,one);for(inti=k-1;i>0;--i){RT1[i-1]=mul_s(RT1[i],RT1[i],niv,mod);}img=rt1[0],imgniv=img*niv;bwbr={one,0,one,0,one};bwb={rt1[1],0,rt1[0],0,mod-mul_s(rt1[0],rt1[1],niv,mod)};bwbi={rt1i[1],0,rt1i[0],0,mul_s(rt1i[0],rt1i[1],niv,mod)};u32pr=one,pri=one;for(inti=0;i<k-2;++i){constu32r=mul_s(pr,rt1[i+1],niv,mod),ri=mul_s(pri,rt1i[i+1],niv,mod);constu32r2=mul_s(r,r,niv,mod),r2i=mul_s(ri,ri,niv,mod);constu32r3=mul_s(r,r2,niv,mod),r3i=mul_s(ri,r2i,niv,mod);rt3[i]={r*niv,r,r2*niv,r2,r3*niv,r3};rt3i[i]={ri*niv,ri,r2i*niv,r2i,r3i*niv,r3i};pr=mul(pr,rt1i[i+1],niv,mod),pri=mul(pri,rt1[i+1],niv,mod);}pr=one,pri=one;for(inti=0;i<k-3;++i){constu32r=mul_s(pr,rt1[i+2],niv,mod),ri=mul_s(pri,rt1i[i+2],niv,mod);rt4[i][0]=rt4i[i][0]=one;for(intj=1;j<8;++j){rt4[i][j]=mul_s(rt4[i][j-1],r,niv,mod);rt4i[i][j]=mul_s(rt4i[i][j-1],ri,niv,mod);}for(intj=0;j<8;++j){rt4niv[i][j]=rt4[i][j]*niv;rt4iniv[i][j]=rt4i[i][j]*niv;}pr=mul(pr,rt1i[i+2],niv,mod),pri=mul(pri,rt1[i+2],niv,mod);}pr2={one,one,one,img,one,one,one,img};pr4={one,one,one,one,one,rt1[1],img,mul_s(img,rt1[1],niv,mod)};constu32nr2=mod-r2,imgr2=mul_s(img,r2,niv,mod);pr2i={nr2,nr2,nr2,imgr2,nr2,nr2,nr2,imgr2};pr4i={one,one,one,one,one,rt1i[1],rt1i[0],mul_s(rt1i[0],rt1i[1],niv,mod)};for(intj=0;j<8;++j){pr2niv[j]=pr2[j]*niv,pr4niv[j]=pr4[j]*niv;pr2iniv[j]=pr2i[j]*niv,pr4iniv[j]=pr4i[j]*niv;}}};inlinevoidvector_dif(I256*constf,constidtn,constFNTT32_info*info){alignas(32)std::array<u32,8>st_1[_mxlg>>1];constI256Mod=_mm256_set1_epi32(info->mod),Mod2=_mm256_set1_epi32(info->mod2),Niv=_mm256_set1_epi32(info->niv);constI256Img=_mm256_set1_epi32(info->img),ImgNiv=_mm256_set1_epi32(info->imgniv),id=_mm256_setr_epi32(0,2,0,4,0,2,0,4);constintlgn=__builtin_ctzll(n);std::fill(st_1,st_1+(lgn>>1),info->bwb);constidtnn=n>>(lgn&1),m=std::min(n,_itth),mm=std::min(nn,_itth);// I256 rr=_mm256_set1_epi32(info->one);if(nn!=n){for(idti=0;i<nn;++i){autoconstp0=f+i,p1=f+nn+i;constautof0=load256(p0),f1=load256(p1);constautog0=add32(f0,f1,Mod2),g1=Lsub32(f0,f1,Mod2);store256(p0,g0),store256(p1,g1);}}for(idtL=nn>>2;L>0;L>>=2){for(idti=0;i<L;++i){autoconstp0=f+i,p1=p0+L,p2=p1+L,p3=p2+L;constautof1=load256(p1),f3=load256(p3),f2=load256(p2),f0=load256(p0);constautog3=mul_bsmfxd(Lsub32(f1,f3,Mod2),Img,ImgNiv,Mod),g1=add32(f1,f3,Mod2);constautog0=add32(f0,f2,Mod2),g2=sub32(f0,f2,Mod2);constautoh0=add32(g0,g1,Mod2),h1=Lsub32(g0,g1,Mod2);constautoh2=Ladd32(g2,g3,Mod2),h3=Lsub32(g2,g3,Mod2);store256(p0,h0),store256(p1,h1),store256(p2,h2),store256(p3,h3);}}for(idtj=0;j<n;j+=m){intt=((j==0)?std::min(_lg_itth,lgn):__builtin_ctzll(j))&-2,p=(t-2)>>1;for(idtL=(idt(1)<<t)>>2;L>=_itth;L>>=2,t-=2,--p){autort=load256(st_1+p);constautor1=_mm256_permutevar8x32_epi32(rt,id);constautor1Niv=_mm256_permutevar8x32_epi32(_mm256_mul_epu32(rt,Niv),id);rt=mul_upd_rt(rt,load256(info->rt3+__builtin_ctzll(~j>>t)),Mod);constautor2=_mm256_shuffle_epi32(r1,_MM_PERM_BBBB),nr3=_mm256_shuffle_epi32(r1,_MM_PERM_DDDD);constautor2Niv=_mm256_shuffle_epi32(r1Niv,_MM_PERM_BBBB),nr3Niv=_mm256_shuffle_epi32(r1Niv,_MM_PERM_DDDD);store256(st_1+p,rt);for(idti=0;i<L;++i){autoconstp0=f+i+j,p1=p0+L,p2=p1+L,p3=p2+L;constautof1=load256(p1),f3=load256(p3),f2=load256(p2),f0=load256(p0);constautog1=mul_bsmfxd(f1,r1,r1Niv,Mod),ng3=mul_bsmfxd(f3,nr3,nr3Niv,Mod);constautog2=mul_bsmfxd(f2,r2,r2Niv,Mod),g0=shrk32(f0,Mod2);constautoh3=mul_bsmfxd(Ladd32(g1,ng3,Mod2),Img,ImgNiv,Mod),h1=sub32(g1,ng3,Mod2);constautoh0=add32(g0,g2,Mod2),h2=sub32(g0,g2,Mod2);constautou0=Ladd32(h0,h1,Mod2),u1=Lsub32(h0,h1,Mod2);constautou2=Ladd32(h2,h3,Mod2),u3=Lsub32(h2,h3,Mod2);store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);}}I256*constg=f+j;for(idtl=mm,L=mm>>2;L;l=L,L>>=2,t-=2,--p){autort=load256(st_1+p);for(idti=(j==0?l:0),k=(j+i)>>t;i<m;i+=l,++k){constautor1=_mm256_permutevar8x32_epi32(rt,id);constautor2=_mm256_shuffle_epi32(r1,_MM_PERM_BBBB);constautonr3=_mm256_shuffle_epi32(r1,_MM_PERM_DDDD);for(idtj=0;j<L;++j){autoconstp0=g+i+j,p1=p0+L,p2=p1+L,p3=p2+L;constautof1=load256(p1),f3=load256(p3),f2=load256(p2),f0=load256(p0);constautog1=mul_bsm(f1,r1,Niv,Mod),ng3=mul_bsm(f3,nr3,Niv,Mod);constautog2=mul_bsm(f2,r2,Niv,Mod),g0=shrk32(f0,Mod2);constautoh3=mul_bsmfxd(Ladd32(g1,ng3,Mod2),Img,ImgNiv,Mod),h1=sub32(g1,ng3,Mod2);constautoh0=add32(g0,g2,Mod2),h2=sub32(g0,g2,Mod2);constautou0=Ladd32(h0,h1,Mod2),u1=Lsub32(h0,h1,Mod2);constautou2=Ladd32(h2,h3,Mod2),u3=Lsub32(h2,h3,Mod2);store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);}rt=mul_upd_rt(rt,load256(info->rt3+__builtin_ctzll(~k)),Mod);}store256(st_1+p,rt);}// const auto pr2=load256(&info->pr2),pr4=load256(&info->pr4);// const auto pr2Niv=load256(&info->pr2niv),pr4Niv=load256(&info->pr4niv);// for(idt i=j;i<j+m;++i){// auto fi=load256(f+i);// fi=mul(fi,rr,Niv,Mod);// rr=shrk32(mul_bfxd(rr,load256(info->rt4+__builtin_ctzll(~i)),load256(info->rt4niv+__builtin_ctzll(~i)),Mod),Mod);// fi=mul_bfxd(Ladd32(neg32_m<0xf0>(fi,Mod2),_mm256_permute2x128_si256(fi,fi,1),Mod2),pr4,pr4Niv,Mod);// fi=mul_bfxd(Ladd32(neg32_m<0xcc>(fi,Mod2),_mm256_shuffle_epi32(fi,0x4e),Mod2),pr2,pr2Niv,Mod);// fi=sub32(_mm256_shuffle_epi32(fi,0xb1),neg32_m<0x55>(fi,Mod2),Mod2);// store256(f+i,fi);// }}}template<boolshrk=false>inlinevoidvector_dit(I256*constf,idtn,constFNTT32_info*constinfo){alignas(32)std::array<u32,8>st_1[_mxlg>>1];constI256Mod=_mm256_set1_epi32(info->mod),Mod2=_mm256_set1_epi32(info->mod2),Niv=_mm256_set1_epi32(info->niv);constI256Img=_mm256_set1_epi32(info->img),ImgNiv=_mm256_set1_epi32(info->imgniv),id=_mm256_setr_epi32(0,2,0,4,0,2,0,4);constintlgn=__builtin_ctzll(n);std::fill(st_1,st_1+(_lg_itth>>1),info->bwbr);std::fill(st_1+(_lg_itth>>1),st_1+(_mxlg>>1),info->bwbi);constidtnn=n>>(lgn&1),mm=std::min(nn,_itth);// I256 rr=_mm256_set1_epi32((info->mod-1)>>(lgn+3));for(idtj=0;j<n;j+=mm){// const auto pr2=load256(&info->pr2i),pr4=load256(&info->pr4i);// const auto pr2Niv=load256(&info->pr2iniv),pr4Niv=load256(&info->pr4iniv);// for(idt i=j;i<j+mm;++i){// auto fi=load256(f+i);// const auto rt=rr;// rr=shrk32(mul_bfxd(rr,load256(info->rt4i+__builtin_ctzll(~i)),load256(info->rt4iniv+__builtin_ctzll(~i)),Mod),Mod);// fi=mul_bfxd(Ladd32(neg32_m<0xaa>(fi,Mod2),_mm256_shuffle_epi32(fi,0xb1),Mod2),pr2,pr2Niv,Mod);// fi=mul_bfxd(Ladd32(neg32_m<0xcc>(fi,Mod2),_mm256_shuffle_epi32(fi,0x4e),Mod2),pr4,pr4Niv,Mod);// fi=mul(Ladd32(neg32_m<0xf0>(fi,Mod2),_mm256_permute2x128_si256(fi,fi,1),Mod2),rt,Niv,Mod);// store256(f+i,fi);// }I256*constg=f+j;intt=2,p=0;for(idtl=4,L=1;l<=mm;L=l,l<<=2,t+=2,++p){autort=load256(st_1+p);for(idti=0,k=j>>t;i<mm;i+=l,++k){constautor1=_mm256_permutevar8x32_epi32(rt,id);constautor2=_mm256_shuffle_epi32(r1,_MM_PERM_BBBB);constautor3=_mm256_shuffle_epi32(r1,_MM_PERM_DDDD);for(idtj=0;j<L;++j){autoconstp0=g+i+j,p1=p0+L,p2=p1+L,p3=p2+L;constautof0=load256(p0),f1=load256(p1),f2=load256(p2),f3=load256(p3);constautog0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);constautog2=add32(f2,f3,Mod2),g3=mul_bsmfxd(Lsub32(f3,f2,Mod2),Img,ImgNiv,Mod);constautoh0=Ladd32(g0,g2,Mod2),h1=Ladd32(g1,g3,Mod2);constautoh2=Lsub32(g0,g2,Mod2),h3=Lsub32(g1,g3,Mod2);constautou0=shrk32(h0,Mod2),u1=mul_bsm(h1,r1,Niv,Mod);constautou2=mul_bsm(h2,r2,Niv,Mod),u3=mul_bsm(h3,r3,Niv,Mod);store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);}rt=mul_upd_rt(rt,load256(info->rt3i+__builtin_ctzll(~k)),Mod);}store256(st_1+p,rt);}inttt=std::min(__builtin_ctzll(~(j>>_lg_itth))+_lg_itth,lgn);for(idtL=_itth,l=L<<2;t<=tt;L=l,l<<=2,t+=2,++p){if((j+_itth)==l){if(shrk&&l==n){for(idti=0;i<L;++i){autoconstp0=f+i,p1=p0+L,p2=p1+L,p3=p2+L;constautof2=load256(p2),f3=load256(p3),f0=load256(p0),f1=load256(p1);constautog3=mul_bsmfxd(Lsub32(f3,f2,Mod2),Img,ImgNiv,Mod),g2=add32(f2,f3,Mod2);constautog0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);constautoh0=add32(g0,g2,Mod2),h1=add32(g1,g3,Mod2);constautoh2=sub32(g0,g2,Mod2),h3=sub32(g1,g3,Mod2);constautou0=shrk32(h0,Mod),u1=shrk32(h1,Mod);constautou2=shrk32(h2,Mod),u3=shrk32(h3,Mod);store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);}}else{for(idti=0;i<L;++i){autoconstp0=f+i,p1=p0+L,p2=p1+L,p3=p2+L;constautof2=load256(p2),f3=load256(p3),f0=load256(p0),f1=load256(p1);constautog3=mul_bsmfxd(Lsub32(f3,f2,Mod2),Img,ImgNiv,Mod),g2=add32(f2,f3,Mod2);constautog0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);constautoh0=add32(g0,g2,Mod2),h1=add32(g1,g3,Mod2);constautoh2=sub32(g0,g2,Mod2),h3=sub32(g1,g3,Mod2);store256(p0,h0),store256(p1,h1),store256(p2,h2),store256(p3,h3);}}}else{autort=load256(st_1+p);constautor1=_mm256_permutevar8x32_epi32(rt,id);constautor1Niv=_mm256_permutevar8x32_epi32(_mm256_mul_epu32(rt,Niv),id);rt=mul_upd_rt(rt,load256(info->rt3i+__builtin_ctzll(~j>>t)),Mod);constautor2=_mm256_shuffle_epi32(r1,_MM_PERM_BBBB),r3=_mm256_shuffle_epi32(r1,_MM_PERM_DDDD);constautor2Niv=_mm256_shuffle_epi32(r1Niv,_MM_PERM_BBBB),r3Niv=_mm256_shuffle_epi32(r1Niv,_MM_PERM_DDDD);store256(st_1+p,rt);for(idti=0;i<L;++i){autoconstp0=f+j+_itth-l+i,p1=p0+L,p2=p1+L,p3=p2+L;constautof0=load256(p0),f1=load256(p1),f2=load256(p2),f3=load256(p3);constautog0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);constautog2=add32(f2,f3,Mod2),g3=mul_bsmfxd(Lsub32(f3,f2,Mod2),Img,ImgNiv,Mod);constautoh0=Ladd32(g0,g2,Mod2),h1=Ladd32(g1,g3,Mod2);constautoh2=Lsub32(g0,g2,Mod2),h3=Lsub32(g1,g3,Mod2);constautou0=shrk32(h0,Mod2),u1=mul_bsmfxd(h1,r1,r1Niv,Mod);constautou2=mul_bsmfxd(h2,r2,r2Niv,Mod),u3=mul_bsmfxd(h3,r3,r3Niv,Mod);store256(p0,u0),store256(p1,u1),store256(p2,u2),store256(p3,u3);}}}}if(shrk&&nn==n&&n<=_itth){for(idti=0;i<n;++i){constautof0=load256(f+i);store256(f+i,shrk32(f0,Mod));}}if(nn!=n){for(idti=0;i<nn;++i){autoconstp0=f+i,p1=f+nn+i;constautof0=load256(p0),f1=load256(p1);constautog0=add32(f0,f1,Mod2),g1=sub32(f0,f1,Mod2);ifconstexpr(shrk){constautoh0=shrk32(g0,Mod),h1=shrk32(g1,Mod);store256(p0,h0),store256(p1,h1);}else{store256(p0,g0),store256(p1,g1);}}}}// Returns fx * f[0,8) * g[0,8) (mod x^8 - ww).[[gnu::always_inline]]inlineI256convolve8(constI256*f,constI256*g,I256ww,I256fx,I256Niv,I256Mod,I256Mod2){constautoraa=load256(f),rbb=load256(g);constautotaa=shrk32(raa,Mod2),bb=shrk32(mul_bsm(rbb,fx,Niv,Mod),Mod);constautoaw=shrk32(mul_bsm(taa,ww,Niv,Mod),Mod);constautoaa=shrk32(taa,Mod);constautoawa=_mm256_permute2x128_si256(aa,aw,3);constautob0=_mm256_permute4x64_epi64(bb,0x00),b1=_mm256_shuffle_epi32(b0,_MM_PERM_CDAB);constautoa0=aa,a1=_mm256_srli_epi64(a0,32);constautoaw7=_mm256_alignr_epi8(aa,awa,12);autores00=_mm256_mul_epu32(a0,b0);autores01=_mm256_mul_epu32(a1,b0);autores10=_mm256_mul_epu32(aw7,b1);autores11=_mm256_mul_epu32(a0,b1);constautob2=_mm256_permute4x64_epi64(bb,0x55),b3=_mm256_shuffle_epi32(b2,_MM_PERM_CDAB);constautoaw6=_mm256_alignr_epi8(aa,awa,8);constautoaw5=_mm256_alignr_epi8(aa,awa,4);res00=_mm256_add_epi64(res00,_mm256_mul_epu32(aw6,b2));res01=_mm256_add_epi64(res01,_mm256_mul_epu32(aw7,b2));res10=_mm256_add_epi64(res10,_mm256_mul_epu32(aw5,b3));res11=_mm256_add_epi64(res11,_mm256_mul_epu32(aw6,b3));constautob4=_mm256_permute4x64_epi64(bb,0xaa),b5=_mm256_shuffle_epi32(b4,_MM_PERM_CDAB);constautoaw3=_mm256_alignr_epi8(awa,aw,12);res00=_mm256_add_epi64(res00,_mm256_mul_epu32(awa,b4));res01=_mm256_add_epi64(res01,_mm256_mul_epu32(aw5,b4));res10=_mm256_add_epi64(res10,_mm256_mul_epu32(aw3,b5));res11=_mm256_add_epi64(res11,_mm256_mul_epu32(awa,b5));constautob6=_mm256_permute4x64_epi64(bb,0xff),b7=_mm256_shuffle_epi32(b6,_MM_PERM_CDAB);constautoaw2=_mm256_alignr_epi8(awa,aw,8);constautoaw1=_mm256_alignr_epi8(awa,aw,4);res00=_mm256_add_epi64(res00,_mm256_mul_epu32(aw2,b6));res01=_mm256_add_epi64(res01,_mm256_mul_epu32(aw3,b6));res10=_mm256_add_epi64(res10,_mm256_mul_epu32(aw1,b7));res11=_mm256_add_epi64(res11,_mm256_mul_epu32(aw2,b7));res00=_mm256_add_epi64(res00,res10);res01=_mm256_add_epi64(res01,res11);returnshrk32(reduce(res00,res01,Niv,Mod),Mod2);}inlinevoidvector_convolution_direct(I256*f,constI256*g,idtlm,constFNTT32_info*constinfo){u32RR=info->one;constautomod=info->mod,niv=info->niv;constautoFx=_mm256_set1_epi32(mul_s((mod-((mod-1)>>(__builtin_ctzll(lm)))),info->r3,niv,mod));constautoNiv=_mm256_set1_epi32(niv),Mod=_mm256_set1_epi32(mod),Mod2=_mm256_set1_epi32(info->mod2);for(idti=0;i<lm;++i){store256(f+i,convolve8(f+i,g+i,_mm256_set1_epi32(RR),Fx,Niv,Mod,Mod2));RR=mul(RR,info->RT1[__builtin_ctzll(~i)],niv,mod);}}inlinevoidvector_convolution_accumulate(I256*constresult,constI256*constf,constI256*constg,idtlm,constFNTT32_info*constinfo){u32RR=info->one;constautomod=info->mod,niv=info->niv;constautoFx=_mm256_set1_epi32(mul_s((mod-((mod-1)>>(__builtin_ctzll(lm)))),info->r3,niv,mod));constautoNiv=_mm256_set1_epi32(niv),Mod=_mm256_set1_epi32(mod),Mod2=_mm256_set1_epi32(info->mod2);for(idti=0;i<lm;++i){constautoproduct=convolve8(f+i,g+i,_mm256_set1_epi32(RR),Fx,Niv,Mod,Mod2);store256(result+i,add32(load256(result+i),product,Mod2));RR=mul(RR,info->RT1[__builtin_ctzll(~i)],niv,mod);}}}// namespace fast998_v2}// namespace internal}// namespace fps}// namespace m1une#endif // M1UNE_FPS_HAS_X86_SIMD
#line 24 "math/fps/convolution.hpp"
#ifdef M1UNE_FPS_HAS_X86_SIMD
#pragma GCC pop_options
#endif
#line 1 "math/modint.hpp"
#line 6 "math/modint.hpp"
#include<iostream>
#line 9 "math/modint.hpp"
namespacem1une{namespacemath{template<uint32_tModulus>structModInt{static_assert(0<Modulus,"Modulus must be positive");private:uint32_t_v;public:staticconstexpruint32_tmod(){returnModulus;}staticconstexprModIntraw(uint32_tv)noexcept{ModIntx;x._v=v;returnx;}constexprModInt()noexcept:_v(0){}template<classInteger,std::enable_if_t<std::is_integral_v<Integer>,int>=0>constexprModInt(Integerv)noexcept{ifconstexpr(std::is_signed_v<Integer>){int64_tx=static_cast<int64_t>(v)%static_cast<int64_t>(Modulus);if(x<0)x+=Modulus;_v=static_cast<uint32_t>(x);}else{_v=static_cast<uint32_t>(static_cast<uint64_t>(v)%Modulus);}}constexpruint32_tval()constnoexcept{return_v;}constexprModInt&operator++()noexcept{_v++;if(_v==Modulus)_v=0;return*this;}constexprModInt&operator--()noexcept{if(_v==0)_v=Modulus;_v--;return*this;}constexprModIntoperator++(int)noexcept{ModIntres=*this;++*this;returnres;}constexprModIntoperator--(int)noexcept{ModIntres=*this;--*this;returnres;}constexprModInt&operator+=(constModInt&rhs)noexcept{_v+=rhs._v;if(_v>=Modulus)_v-=Modulus;return*this;}constexprModInt&operator-=(constModInt&rhs)noexcept{_v-=rhs._v;if(_v>=Modulus)_v+=Modulus;return*this;}constexprModInt&operator*=(constModInt&rhs)noexcept{uint64_tz=_v;z*=rhs._v;_v=static_cast<uint32_t>(z%Modulus);return*this;}constexprModInt&operator/=(constModInt&rhs)noexcept{return*this*=rhs.inv();}constexprModIntoperator+(constModInt&rhs)constnoexcept{returnModInt(*this)+=rhs;}constexprModIntoperator-(constModInt&rhs)constnoexcept{returnModInt(*this)-=rhs;}constexprModIntoperator*(constModInt&rhs)constnoexcept{returnModInt(*this)*=rhs;}constexprModIntoperator/(constModInt&rhs)constnoexcept{returnModInt(*this)/=rhs;}constexprbooloperator==(constModInt&rhs)constnoexcept{return_v==rhs._v;}constexprbooloperator!=(constModInt&rhs)constnoexcept{return_v!=rhs._v;}constexprModIntpow(longlongn)constnoexcept{ModIntres=raw(1%Modulus);ModIntx=n<0?inv():*this;uint64_texponent=n<0?uint64_t(-(n+1))+1:uint64_t(n);while(exponent>0){if(exponent&1)res*=x;x*=x;exponent>>=1;}returnres;}constexprModIntinv()constnoexcept{int64_ta=_v,b=Modulus,u=1,v=0;while(b){int64_tt=a/b;a-=t*b;std::swap(a,b);u-=t*v;std::swap(u,v);}assert(a==1);u%=Modulus;if(u<0)u+=Modulus;returnraw(static_cast<uint32_t>(u));}friendstd::ostream&operator<<(std::ostream&os,constModInt&rhs){returnos<<rhs._v;}friendstd::istream&operator>>(std::istream&is,ModInt&rhs){longlongv;is>>v;rhs=ModInt(v);returnis;}};usingmodint998244353=ModInt<998244353>;usingmodint1000000007=ModInt<1000000007>;template<intId=0>structDynamicModInt{private:uint32_t_v;inlinestaticuint32_t_mod=1;public:staticuint32_tmod()noexcept{return_mod;}staticvoidset_mod(uint32_tmodulus)noexcept{assert(modulus>0);assert(modulus<=uint32_t(1)<<31);_mod=modulus;}staticDynamicModIntraw(uint32_tv)noexcept{assert(v<_mod);DynamicModIntx;x._v=v;returnx;}DynamicModInt()noexcept:_v(0){}template<classInteger,std::enable_if_t<std::is_integral_v<Integer>,int>=0>DynamicModInt(Integerv)noexcept{ifconstexpr(std::is_signed_v<Integer>){int64_tx=static_cast<int64_t>(v)%static_cast<int64_t>(_mod);if(x<0)x+=_mod;_v=static_cast<uint32_t>(x);}else{_v=static_cast<uint32_t>(static_cast<uint64_t>(v)%_mod);}}uint32_tval()constnoexcept{return_v;}DynamicModInt&operator++()noexcept{_v++;if(_v==_mod)_v=0;return*this;}DynamicModInt&operator--()noexcept{if(_v==0)_v=_mod;_v--;return*this;}DynamicModIntoperator++(int)noexcept{DynamicModIntresult=*this;++*this;returnresult;}DynamicModIntoperator--(int)noexcept{DynamicModIntresult=*this;--*this;returnresult;}DynamicModInt&operator+=(constDynamicModInt&rhs)noexcept{_v+=rhs._v;if(_v>=_mod)_v-=_mod;return*this;}DynamicModInt&operator-=(constDynamicModInt&rhs)noexcept{_v-=rhs._v;if(_v>=_mod)_v+=_mod;return*this;}DynamicModInt&operator*=(constDynamicModInt&rhs)noexcept{_v=static_cast<uint32_t>(uint64_t(_v)*rhs._v%_mod);return*this;}DynamicModInt&operator/=(constDynamicModInt&rhs)noexcept{return*this*=rhs.inv();}DynamicModIntoperator+(constDynamicModInt&rhs)constnoexcept{returnDynamicModInt(*this)+=rhs;}DynamicModIntoperator-(constDynamicModInt&rhs)constnoexcept{returnDynamicModInt(*this)-=rhs;}DynamicModIntoperator*(constDynamicModInt&rhs)constnoexcept{returnDynamicModInt(*this)*=rhs;}DynamicModIntoperator/(constDynamicModInt&rhs)constnoexcept{returnDynamicModInt(*this)/=rhs;}booloperator==(constDynamicModInt&rhs)constnoexcept{return_v==rhs._v;}booloperator!=(constDynamicModInt&rhs)constnoexcept{return_v!=rhs._v;}DynamicModIntpow(longlongexponent)constnoexcept{DynamicModIntresult=raw(1%_mod);DynamicModIntbase=exponent<0?inv():*this;uint64_tmagnitude=exponent<0?uint64_t(-(exponent+1))+1:uint64_t(exponent);while(magnitude>0){if(magnitude&1)result*=base;base*=base;magnitude>>=1;}returnresult;}DynamicModIntinv()constnoexcept{int64_ta=_v,b=_mod,u=1,v=0;while(b){int64_tquotient=a/b;a-=quotient*b;std::swap(a,b);u-=quotient*v;std::swap(u,v);}assert(a==1);u%=_mod;if(u<0)u+=_mod;returnraw(static_cast<uint32_t>(u));}friendstd::ostream&operator<<(std::ostream&os,constDynamicModInt&rhs){returnos<<rhs._v;}friendstd::istream&operator>>(std::istream&is,DynamicModInt&rhs){longlongvalue;is>>value;rhs=DynamicModInt(value);returnis;}};}// namespace math}// namespace m1une#line 29 "math/fps/convolution.hpp"
namespacem1une{namespacefps{namespaceinternal{template<classMint,class=void>structhas_static_modulus:std::false_type{};template<classMint>structhas_static_modulus<Mint,std::void_t<decltype(std::integral_constant<uint32_t,Mint::mod()>{})>>:std::true_type{};constexpruint32_tprimitive_root_constexpr(uint32_tmod){if(mod==2)return1;if(mod==167772161)return3;if(mod==469762049)return3;if(mod==754974721)return11;if(mod==998244353)return3;if(mod==1224736769)return3;uint32_tdivisors[32]={};intcount=0;uint32_tx=mod-1;for(uint32_tp=2;uint64_t(p)*p<=x;p++){if(x%p!=0)continue;divisors[count++]=p;while(x%p==0)x/=p;}if(x>1)divisors[count++]=x;for(uint32_tg=2;;g++){boolok=true;for(inti=0;i<count;i++){uint64_tvalue=1;uint64_tbase=g;uint32_texponent=(mod-1)/divisors[i];while(exponent>0){if(exponent&1)value=value*base%mod;base=base*base%mod;exponent>>=1;}if(value==1){ok=false;break;}}if(ok)returng;}}constexprinttwo_adic_order(uint32_tx){intresult=0;while((x&1)==0){x>>=1;result++;}returnresult;}template<classMint>structNttRoots{staticconstexprintmax_base=two_adic_order(Mint::mod()-1);std::array<Mint,max_base+1>root;std::array<Mint,max_base+1>inverse_root;std::array<Mint,max_base>rate;std::array<Mint,max_base>inverse_rate;std::array<Mint,max_base>rate_radix4;std::array<Mint,max_base>inverse_rate_radix4;NttRoots(){constexpruint32_tprimitive_root=primitive_root_constexpr(Mint::mod());for(intlevel=1;level<=max_base;level++){root[level]=Mint(primitive_root).pow((Mint::mod()-1)>>level);inverse_root[level]=root[level].inv();}Mintproduct=1;Mintinverse_product=1;for(inti=0;i+1<max_base;i++){rate[i]=root[i+2]*product;inverse_rate[i]=inverse_root[i+2]*inverse_product;product*=inverse_root[i+2];inverse_product*=root[i+2];}product=1;inverse_product=1;for(inti=0;i+2<max_base;i++){rate_radix4[i]=root[i+3]*product;inverse_rate_radix4[i]=inverse_root[i+3]*inverse_product;product*=inverse_root[i+3];inverse_product*=root[i+3];}}};template<classMint>constNttRoots<Mint>&ntt_roots(){staticconstNttRoots<Mint>roots;returnroots;}template<classMint>voidntt(std::vector<Mint>&a,boolinverse,boolnormalize=true){constintn=int(a.size());assert(n>0&&(n&(n-1))==0);assert((Mint::mod()-1)%uint32_t(n)==0);constauto&roots=ntt_roots<Mint>();constintheight=two_adic_order(uint32_t(n));if(!inverse){intphase=0;while(phase<height){if(height-phase==1){constintwidth=1<<(height-phase-1);Minttwiddle=1;for(intblock=0;block<(1<<phase);block++){constintoffset=block<<(height-phase);for(inti=0;i<width;i++){constMintleft=a[offset+i];constMintright=a[offset+i+width]*twiddle;a[offset+i]=left+right;a[offset+i+width]=left-right;}if(block+1!=(1<<phase))twiddle*=roots.rate[__builtin_ctz(~uint32_t(block))];}phase++;continue;}constintwidth=1<<(height-phase-2);Minttwiddle=1;constMintimaginary=roots.root[2];for(intblock=0;block<(1<<phase);block++){constMinttwiddle2=twiddle*twiddle;constMinttwiddle3=twiddle2*twiddle;constintoffset=block<<(height-phase);for(inti=0;i<width;i++){constuint64_tmod2=uint64_t(Mint::mod())*Mint::mod();constuint64_ta0=a[offset+i].val();constuint64_ta1=uint64_t(a[offset+i+width].val())*twiddle.val();constuint64_ta2=uint64_t(a[offset+i+2*width].val())*twiddle2.val();constuint64_ta3=uint64_t(a[offset+i+3*width].val())*twiddle3.val();constuint64_ta1na3i=uint64_t(Mint(a1+mod2-a3).val())*imaginary.val();constuint64_tnegative_a2=mod2-a2;a[offset+i]=Mint(a0+a2+a1+a3);a[offset+i+width]=Mint(a0+a2+2*mod2-a1-a3);a[offset+i+2*width]=Mint(a0+negative_a2+a1na3i);a[offset+i+3*width]=Mint(a0+negative_a2+mod2-a1na3i);}if(block+1!=(1<<phase))twiddle*=roots.rate_radix4[__builtin_ctz(~uint32_t(block))];}phase+=2;}}else{intphase=height;while(phase>0){if(phase==1){constintwidth=1<<(height-phase);Minttwiddle=1;for(intblock=0;block<(1<<(phase-1));block++){constintoffset=block<<(height-phase+1);for(inti=0;i<width;i++){constMintleft=a[offset+i];constMintright=a[offset+i+width];a[offset+i]=left+right;a[offset+i+width]=(left-right)*twiddle;}if(block+1!=(1<<(phase-1)))twiddle*=roots.inverse_rate[__builtin_ctz(~uint32_t(block))];}phase--;continue;}constintwidth=1<<(height-phase);Minttwiddle=1;constMintinverse_imaginary=roots.inverse_root[2];for(intblock=0;block<(1<<(phase-2));block++){constMinttwiddle2=twiddle*twiddle;constMinttwiddle3=twiddle2*twiddle;constintoffset=block<<(height-phase+2);for(inti=0;i<width;i++){constuint64_ta0=a[offset+i].val();constuint64_ta1=a[offset+i+width].val();constuint64_ta2=a[offset+i+2*width].val();constuint64_ta3=a[offset+i+3*width].val();constuint64_ta2na3i=uint64_t(Mint((Mint::mod()+a2-a3)*inverse_imaginary.val()).val());a[offset+i]=Mint(a0+a1+a2+a3);a[offset+i+width]=Mint((a0+Mint::mod()-a1+a2na3i)*twiddle.val());a[offset+i+2*width]=Mint((a0+a1+2ULL*Mint::mod()-a2-a3)*twiddle2.val());a[offset+i+3*width]=Mint((a0+Mint::mod()-a1+Mint::mod()-a2na3i)*twiddle3.val());}if(block+1!=(1<<(phase-2)))twiddle*=roots.inverse_rate_radix4[__builtin_ctz(~uint32_t(block))];}phase-=2;}if(normalize){constMintinverse_n=Mint(n).inv();for(Mint&value:a)value*=inverse_n;}}}#ifdef M1UNE_FPS_HAS_X86_SIMD
#pragma GCC push_options
#pragma GCC target("avx2,bmi")
template<classMint>__attribute__((target("avx2,bmi"),hot))std::vector<Mint>convolution_998244353_simd(conststd::vector<Mint>&a,conststd::vector<Mint>&b){constintresult_size=int(a.size()+b.size()-1);intn=1;while(n<result_size)n<<=1;constboolsquaring=&a==&b;auto*transformed_a=static_cast<uint32_t*>(::operatornew[](sizeof(uint32_t)*n,std::align_val_t(32)));auto*transformed_b=squaring?transformed_a:static_cast<uint32_t*>(::operatornew[](sizeof(uint32_t)*n,std::align_val_t(32)));ifconstexpr(std::is_same_v<Mint,math::ModInt<998244353>>){static_assert(sizeof(Mint)==sizeof(uint32_t)&&std::is_trivially_copyable_v<Mint>);std::memcpy(transformed_a,a.data(),sizeof(uint32_t)*a.size());if(!squaring)std::memcpy(transformed_b,b.data(),sizeof(uint32_t)*b.size());}else{for(inti=0;i<int(a.size());i++)transformed_a[i]=a[i].val();if(!squaring)for(inti=0;i<int(b.size());i++)transformed_b[i]=b[i].val();}std::memset(transformed_a+a.size(),0,sizeof(uint32_t)*(n-a.size()));if(!squaring)std::memset(transformed_b+b.size(),0,sizeof(uint32_t)*(n-b.size()));staticconstexprfast998_v2::FNTT32_infotransform(998244353);conststd::size_tvector_size=std::size_t(n)>>3;fast998_v2::vector_dif(reinterpret_cast<__m256i*>(transformed_a),vector_size,&transform);if(!squaring)fast998_v2::vector_dif(reinterpret_cast<__m256i*>(transformed_b),vector_size,&transform);fast998_v2::vector_convolution_direct(reinterpret_cast<__m256i*>(transformed_a),reinterpret_cast<const__m256i*>(transformed_b),vector_size,&transform);fast998_v2::vector_dit<true>(reinterpret_cast<__m256i*>(transformed_a),vector_size,&transform);std::vector<Mint>result(result_size);for(intj=0;j<result_size;j++)result[j]=Mint::raw(transformed_a[j]);::operatordelete[](transformed_a,std::align_val_t(32));if(!squaring)::operatordelete[](transformed_b,std::align_val_t(32));returnresult;}#pragma GCC pop_options
#endif
}// namespace internaltemplate<classMint>std::vector<Mint>convolution_naive(conststd::vector<Mint>&a,conststd::vector<Mint>&b){if(a.empty()||b.empty())return{};std::vector<Mint>result(a.size()+b.size()-1);if(a.size()<b.size()){for(inti=0;i<int(a.size());i++){for(intj=0;j<int(b.size());j++)result[i+j]+=a[i]*b[j];}}else{for(intj=0;j<int(b.size());j++){for(inti=0;i<int(a.size());i++)result[i+j]+=a[i]*b[j];}}returnresult;}template<classMint>std::vector<Mint>convolution_ntt(conststd::vector<Mint>&a,conststd::vector<Mint>&b){constintresult_size=int(a.size()+b.size()-1);intn=1;while(n<result_size)n<<=1;assert((Mint::mod()-1)%uint32_t(n)==0);#ifdef M1UNE_FPS_HAS_X86_SIMD
ifconstexpr(Mint::mod()==998244353){if(n>=64&&__builtin_cpu_supports("avx2"))returninternal::convolution_998244353_simd(a,b);}#endif
// Allocate the padded buffers directly. Constructing from the inputs and// then resizing used to allocate and copy both large operands twice.constboolsquaring=&a==&b;std::vector<Mint>fa(n);std::copy(a.begin(),a.end(),fa.begin());internal::ntt(fa,false);constMintinverse_n=Mint(n).inv();if(squaring){for(inti=0;i<n;i++)fa[i]*=fa[i]*inverse_n;}else{std::vector<Mint>fb(n);std::copy(b.begin(),b.end(),fb.begin());internal::ntt(fb,false);for(inti=0;i<n;i++)fa[i]*=fb[i]*inverse_n;}internal::ntt(fa,true,false);fa.resize(result_size);returnfa;}namespaceinternal{template<classMint>std::vector<Mint>convolution_998244353_blocked_scalar(conststd::vector<Mint>&a,conststd::vector<Mint>&b,inttransform_size){assert(Mint::mod()==998244353);assert(transform_size>=2&&(transform_size&(transform_size-1))==0);assert((Mint::mod()-1)%uint32_t(transform_size)==0);constintblock_size=transform_size/2;constinta_blocks=int((a.size()+block_size-1)/block_size);constintb_blocks=int((b.size()+block_size-1)/block_size);autotransform_blocks=[&](conststd::vector<Mint>&values,intblock_count){std::vector<std::vector<Mint>>blocks;blocks.reserve(block_count);for(intblock=0;block<block_count;block++){constintbegin=block*block_size;constintcount=std::min(block_size,int(values.size())-begin);std::vector<Mint>transformed(transform_size);std::copy_n(values.begin()+begin,count,transformed.begin());ntt(transformed,false);blocks.emplace_back(std::move(transformed));}returnblocks;};std::vector<std::vector<Mint>>transformed_a=transform_blocks(a,a_blocks);std::vector<std::vector<Mint>>transformed_b=transform_blocks(b,b_blocks);constintresult_size=int(a.size()+b.size()-1);std::vector<Mint>result(result_size);std::vector<Mint>transformed_result(transform_size);for(intdiagonal=0;diagonal<a_blocks+b_blocks-1;diagonal++){std::fill(transformed_result.begin(),transformed_result.end(),Mint(0));constintfirst_a=std::max(0,diagonal-(b_blocks-1));constintlast_a=std::min(a_blocks-1,diagonal);for(inta_block=first_a;a_block<=last_a;a_block++){constintb_block=diagonal-a_block;for(inti=0;i<transform_size;i++)transformed_result[i]+=transformed_a[a_block][i]*transformed_b[b_block][i];}ntt(transformed_result,true);constintoutput_offset=diagonal*block_size;constintoutput_count=std::min(transform_size,result_size-output_offset);for(inti=0;i<output_count;i++)result[output_offset+i]+=transformed_result[i];}returnresult;}#ifdef M1UNE_FPS_HAS_X86_SIMD
classAlignedUint32Buffer{private:uint32_t*data_;public:explicitAlignedUint32Buffer(std::size_tsize):data_(static_cast<uint32_t*>(::operatornew[](sizeof(uint32_t)*size,std::align_val_t(32)))){}AlignedUint32Buffer(constAlignedUint32Buffer&)=delete;AlignedUint32Buffer&operator=(constAlignedUint32Buffer&)=delete;AlignedUint32Buffer(AlignedUint32Buffer&&other)noexcept:data_(other.data_){other.data_=nullptr;}AlignedUint32Buffer&operator=(AlignedUint32Buffer&&other)noexcept{if(this==&other)return*this;::operatordelete[](data_,std::align_val_t(32));data_=other.data_;other.data_=nullptr;return*this;}~AlignedUint32Buffer(){::operatordelete[](data_,std::align_val_t(32));}uint32_t*data(){returndata_;}constuint32_t*data()const{returndata_;}};template<classMint>__attribute__((target("avx2,bmi"),hot))std::vector<Mint>convolution_998244353_blocked_simd(conststd::vector<Mint>&a,conststd::vector<Mint>&b,inttransform_size){assert(Mint::mod()==998244353);assert(transform_size>=64&&(transform_size&(transform_size-1))==0);assert((Mint::mod()-1)%uint32_t(transform_size)==0);constintblock_size=transform_size/2;constinta_blocks=int((a.size()+block_size-1)/block_size);constintb_blocks=int((b.size()+block_size-1)/block_size);staticconstexprfast998_v2::FNTT32_infotransform(998244353);conststd::size_tvector_size=std::size_t(transform_size)/8;autotransform_blocks=[&](conststd::vector<Mint>&values,intblock_count){std::vector<AlignedUint32Buffer>blocks;blocks.reserve(block_count);for(intblock=0;block<block_count;block++){constintbegin=block*block_size;constintcount=std::min(block_size,int(values.size())-begin);AlignedUint32Buffertransformed(transform_size);ifconstexpr(std::is_same_v<Mint,math::ModInt<998244353>>){static_assert(sizeof(Mint)==sizeof(uint32_t)&&std::is_trivially_copyable_v<Mint>);std::memcpy(transformed.data(),values.data()+begin,sizeof(uint32_t)*count);}else{for(inti=0;i<count;i++)transformed.data()[i]=values[begin+i].val();}std::memset(transformed.data()+count,0,sizeof(uint32_t)*(transform_size-count));fast998_v2::vector_dif(reinterpret_cast<__m256i*>(transformed.data()),vector_size,&transform);blocks.emplace_back(std::move(transformed));}returnblocks;};std::vector<AlignedUint32Buffer>transformed_a=transform_blocks(a,a_blocks);std::vector<AlignedUint32Buffer>transformed_b=transform_blocks(b,b_blocks);constintresult_size=int(a.size()+b.size()-1);std::vector<Mint>result(result_size);AlignedUint32Buffertransformed_result(transform_size);for(intdiagonal=0;diagonal<a_blocks+b_blocks-1;diagonal++){std::memset(transformed_result.data(),0,sizeof(uint32_t)*transform_size);constintfirst_a=std::max(0,diagonal-(b_blocks-1));constintlast_a=std::min(a_blocks-1,diagonal);for(inta_block=first_a;a_block<=last_a;a_block++){constintb_block=diagonal-a_block;fast998_v2::vector_convolution_accumulate(reinterpret_cast<__m256i*>(transformed_result.data()),reinterpret_cast<const__m256i*>(transformed_a[a_block].data()),reinterpret_cast<const__m256i*>(transformed_b[b_block].data()),vector_size,&transform);}fast998_v2::vector_dit<true>(reinterpret_cast<__m256i*>(transformed_result.data()),vector_size,&transform);constintoutput_offset=diagonal*block_size;constintoutput_count=std::min(transform_size,result_size-output_offset);for(inti=0;i<output_count;i++){uint32_tvalue=result[output_offset+i].val()+transformed_result.data()[i];if(value>=Mint::mod())value-=Mint::mod();result[output_offset+i]=Mint::raw(value);}}returnresult;}#endif
template<classMint>std::vector<Mint>convolution_998244353_blocked(conststd::vector<Mint>&a,conststd::vector<Mint>&b,inttransform_size=1<<23){#ifdef M1UNE_FPS_HAS_X86_SIMD
if(transform_size>=64&&__builtin_cpu_supports("avx2"))returnconvolution_998244353_blocked_simd(a,b,transform_size);#endif
returnconvolution_998244353_blocked_scalar(a,b,transform_size);}}// namespace internaltemplate<classMint>std::vector<Mint>convolution(conststd::vector<Mint>&a,conststd::vector<Mint>&b){if(a.empty()||b.empty())return{};if(std::min(a.size(),b.size())<=32)returnconvolution_naive(a,b);constintresult_size=int(a.size()+b.size()-1);intn=1;while(n<result_size)n<<=1;ifconstexpr(internal::has_static_modulus<Mint>::value){ifconstexpr(Mint::mod()==998244353){if(n>(1<<23))returninternal::convolution_998244353_blocked(a,b);}if((Mint::mod()-1)%uint32_t(n)==0)returnconvolution_ntt(a,b);}usingMint1=math::ModInt<167772161>;usingMint2=math::ModInt<469762049>;usingMint3=math::ModInt<754974721>;assert(n<=(1<<24));[[maybe_unused]]constunsigned__int128coefficient_bound=static_cast<unsigned__int128>(std::min(a.size(),b.size()))*(Mint::mod()-1)*(Mint::mod()-1);[[maybe_unused]]constunsigned__int128crt_modulus=static_cast<unsigned__int128>(Mint1::mod())*Mint2::mod()*Mint3::mod();assert(coefficient_bound<crt_modulus);autoconverted_convolution=[&]<classOtherMint>(){std::vector<OtherMint>converted_a(a.size());std::vector<OtherMint>converted_b(b.size());for(inti=0;i<int(a.size());i++)converted_a[i]=OtherMint(a[i].val());for(inti=0;i<int(b.size());i++)converted_b[i]=OtherMint(b[i].val());returnconvolution_ntt(converted_a,converted_b);};std::vector<Mint1>c1=converted_convolution.templateoperator()<Mint1>();std::vector<Mint2>c2=converted_convolution.templateoperator()<Mint2>();std::vector<Mint3>c3=converted_convolution.templateoperator()<Mint3>();staticconstuint64_tinverse_mod1_mod2=Mint2(Mint1::mod()).inv().val();staticconstuint64_tmod1_mod3=Mint1::mod()%Mint3::mod();staticconstuint64_tmod1_mod2_mod3=mod1_mod3*(Mint2::mod()%Mint3::mod())%Mint3::mod();staticconstuint64_tinverse_mod1_mod2_mod3=Mint3(uint32_t(mod1_mod2_mod3)).inv().val();constuint64_ttarget_mod=Mint::mod();constuint64_tmod1_target=Mint1::mod()%target_mod;constuint64_tmod1_mod2_target=mod1_target*(Mint2::mod()%target_mod)%target_mod;std::vector<Mint>result(result_size);for(inti=0;i<result_size;i++){constuint64_tr1=c1[i].val();constuint64_tr2=c2[i].val();constuint64_tr3=c3[i].val();constuint64_tfirst=(r2+Mint2::mod()-r1%Mint2::mod())%Mint2::mod()*inverse_mod1_mod2%Mint2::mod();constuint64_tcombined_mod3=(r1%Mint3::mod()+mod1_mod3*(first%Mint3::mod()))%Mint3::mod();constuint64_tsecond=(r3+Mint3::mod()-combined_mod3)%Mint3::mod()*inverse_mod1_mod2_mod3%Mint3::mod();uint64_tvalue=r1%target_mod;value=(value+mod1_target*(first%target_mod))%target_mod;value=(value+mod1_mod2_target*(second%target_mod))%target_mod;result[i]=Mint::raw(uint32_t(value));}returnresult;}}// namespace fps}// namespace m1une#ifdef M1UNE_FPS_HAS_X86_SIMD
#undef M1UNE_FPS_HAS_X86_SIMD
#endif
#line 14 "graph/tree/distance_frequency.hpp"
namespacem1une{namespacetree{namespacedistance_frequency_detail{template<classMint,classT>std::vector<Mint>count_ordered_pairs(constm1une::graph::Graph<T>&tree,constCentroidDecomposition<T>&decomposition){constintsize=tree.size();std::vector<Mint>count(static_cast<std::size_t>(size));std::vector<char>removed(std::size_t(size),false);std::vector<Mint>histogram;std::vector<std::pair<int,int>>stack;std::vector<int>parent(std::size_t(size),-1);for(intcentroid:decomposition.order){std::vector<Mint>total(1,Mint(1));for(constauto&edge:tree[centroid]){if(!edge.alive||removed[std::size_t(edge.to)])continue;histogram.clear();stack.clear();stack.emplace_back(edge.to,1);parent[std::size_t(edge.to)]=centroid;while(!stack.empty()){constauto[vertex,distance]=stack.back();stack.pop_back();if(int(histogram.size())<=distance){histogram.resize(std::size_t(distance+1));}histogram[std::size_t(distance)]+=Mint(1);for(constauto&next:tree[vertex]){if(!next.alive||removed[std::size_t(next.to)])continue;if(next.to==parent[std::size_t(vertex)])continue;parent[std::size_t(next.to)]=vertex;stack.emplace_back(next.to,distance+1);}}if(total.size()<histogram.size()){total.resize(histogram.size());}for(std::size_tdistance=0;distance<histogram.size();distance++){total[distance]+=histogram[distance];}conststd::vector<Mint>within_component=m1une::fps::convolution(histogram,histogram);conststd::size_tlimit=std::min(count.size(),within_component.size());for(std::size_tdistance=0;distance<limit;distance++){count[distance]-=within_component[distance];}}conststd::vector<Mint>through_centroid=m1une::fps::convolution(total,total);conststd::size_tlimit=std::min(count.size(),through_centroid.size());for(std::size_tdistance=0;distance<limit;distance++){count[distance]+=through_centroid[distance];}removed[std::size_t(centroid)]=true;}returncount;}inlinestd::uint64_tcombine_residues(std::uint32_tfirst,std::uint32_tsecond){usingFirst=m1une::math::ModInt<998244353>;usingSecond=m1une::math::ModInt<924844033>;staticconststd::uint64_tinverse=Second(First::mod()).inv().val();conststd::uint64_toffset=(std::uint64_t(second)+Second::mod()-first%Second::mod())%Second::mod();conststd::uint64_tmultiplier=offset*inverse%Second::mod();returnstd::uint64_t(first)+std::uint64_t(First::mod())*multiplier;}}// namespace distance_frequency_detailtemplate<classT>std::vector<longlong>tree_distance_frequency(constm1une::graph::Graph<T>&tree){constintsize=tree.size();assert(tree.edge_count()==std::max(0,size-1));if(size==0)return{};constCentroidDecomposition<T>decomposition(tree);assert(decomposition.roots.size()==1);usingFirst=m1une::math::ModInt<998244353>;usingSecond=m1une::math::ModInt<924844033>;assert(std::uint64_t(size)*std::uint64_t(size-1)<std::uint64_t(First::mod())*Second::mod());conststd::vector<First>first=distance_frequency_detail::count_ordered_pairs<First>(tree,decomposition);conststd::vector<Second>second=distance_frequency_detail::count_ordered_pairs<Second>(tree,decomposition);std::vector<longlong>result(static_cast<std::size_t>(size));result[0]=size;for(intdistance=1;distance<size;distance++){conststd::uint64_tordered=distance_frequency_detail::combine_residues(first[std::size_t(distance)].val(),second[std::size_t(distance)].val());assert((ordered&1)==0);result[std::size_t(distance)]=static_cast<longlong>(ordered/2);}returnresult;}}// namespace tree}// namespace m1une#line 1 "graph/tree/dsu_on_tree.hpp"
#line 7 "graph/tree/dsu_on_tree.hpp"
#line 9 "graph/tree/dsu_on_tree.hpp"
namespacem1une{namespacetree{template<classT=int>structDsuOnTree{intn;introot;std::vector<int>parent;std::vector<int>parent_edge;std::vector<int>depth;std::vector<int>subtree_size;std::vector<int>heavy_child;std::vector<int>tin;std::vector<int>tout;std::vector<int>order;std::vector<std::vector<int>>children;DsuOnTree():n(0),root(-1){}explicitDsuOnTree(constm1une::graph::Graph<T>&graph,introot_vertex=0){build(graph,root_vertex);}voidbuild(constm1une::graph::Graph<T>&graph,introot_vertex=0){n=graph.size();root=n==0?-1:root_vertex;parent.assign(n,-2);parent_edge.assign(n,-1);depth.assign(n,0);subtree_size.assign(n,1);heavy_child.assign(n,-1);tin.assign(n,-1);tout.assign(n,-1);order.clear();order.reserve(n);children.assign(n,{});if(n==0)return;assert(0<=root&&root<n);std::vector<int>stack;stack.push_back(root);parent[root]=-1;while(!stack.empty()){intvertex=stack.back();stack.pop_back();tin[vertex]=int(order.size());order.push_back(vertex);for(constauto&edge:graph[vertex]){if(!edge.alive||parent[edge.to]!=-2)continue;parent[edge.to]=vertex;parent_edge[edge.to]=edge.id;depth[edge.to]=depth[vertex]+1;children[vertex].push_back(edge.to);stack.push_back(edge.to);}}assert(int(order.size())==n);for(intindex=n-1;index>=0;--index){intvertex=order[index];for(intchild:children[vertex]){subtree_size[vertex]+=subtree_size[child];if(heavy_child[vertex]==-1||subtree_size[heavy_child[vertex]]<subtree_size[child]){heavy_child[vertex]=child;}}tout[vertex]=tin[vertex]+subtree_size[vertex];}}intsize()const{returnn;}boolempty()const{returnn==0;}std::pair<int,int>subtree_range(intvertex)const{assert(0<=vertex&&vertex<n);return{tin[vertex],tout[vertex]};}// Runs DSU on tree. `add(v)` inserts one vertex into the maintained state,// `remove(v)` erases it, and `answer(v)` observes the state for subtree(v).template<classAdd,classRemove,classAnswer>voidrun(Addadd,Removeremove,Answeranswer)const{if(n==0)return;enumActionType{Process,AddSubtree,AddVertex,AnswerVertex,RemoveSubtree,};structAction{ActionTypetype;intvertex;boolkeep;};std::vector<Action>actions;actions.reserve(3*std::size_t(n));actions.push_back(Action{Process,root,true});while(!actions.empty()){Actionaction=actions.back();actions.pop_back();intvertex=action.vertex;if(action.type==AddSubtree){for(intindex=tin[vertex];index<tout[vertex];++index){add(order[index]);}}elseif(action.type==AddVertex){add(vertex);}elseif(action.type==AnswerVertex){answer(vertex);}elseif(action.type==RemoveSubtree){for(intindex=tin[vertex];index<tout[vertex];++index){remove(order[index]);}}else{if(!action.keep){actions.push_back(Action{RemoveSubtree,vertex,false,});}actions.push_back(Action{AnswerVertex,vertex,false});actions.push_back(Action{AddVertex,vertex,false});for(intchild:children[vertex]){if(child!=heavy_child[vertex]){actions.push_back(Action{AddSubtree,child,false,});}}if(heavy_child[vertex]!=-1){actions.push_back(Action{Process,heavy_child[vertex],true,});}for(intchild:children[vertex]){if(child!=heavy_child[vertex]){actions.push_back(Action{Process,child,false});}}}}}};}// namespace tree}// namespace m1une#line 1 "graph/tree/euler_tour.hpp"
#line 8 "graph/tree/euler_tour.hpp"
#line 10 "graph/tree/euler_tour.hpp"
namespacem1une{namespacetree{template<classT=int>structEulerTour{usingcost_type=T;usingedge_type=m1une::graph::Edge<T>;introot;std::vector<int>parent;std::vector<int>parent_edge;std::vector<int>depth;std::vector<T>dist;std::vector<int>subtree_size;std::vector<int>tin;std::vector<int>tout;std::vector<int>order;std::vector<std::vector<int>>children;private:int_n;voidcheck_vertex(intv)const{assert(0<=v&&v<_n);assert(tin[v]!=-1);}public:EulerTour():root(-1),_n(0){}explicitEulerTour(constm1une::graph::Graph<T>&g,introot_=0){build(g,root_);}voidbuild(constm1une::graph::Graph<T>&g,introot_=0){_n=g.size();root=_n==0?-1:root_;parent.assign(_n,-2);parent_edge.assign(_n,-1);depth.assign(_n,0);dist.assign(_n,T(0));subtree_size.assign(_n,0);tin.assign(_n,-1);tout.assign(_n,-1);order.clear();order.reserve(_n);children.assign(_n,{});if(_n==0)return;assert(0<=root&&root<_n);structFrame{intv;intstate;};std::vector<Frame>stack;stack.push_back({root,0});parent[root]=-1;while(!stack.empty()){Frameframe=stack.back();stack.pop_back();intv=frame.v;if(frame.state==0){tin[v]=int(order.size());order.push_back(v);stack.push_back({v,1});constauto&adj=g[v];for(inti=int(adj.size())-1;i>=0;--i){constauto&e=adj[i];if(!e.alive)continue;if(parent[e.to]!=-2)continue;parent[e.to]=v;parent_edge[e.to]=e.id;depth[e.to]=depth[v]+1;dist[e.to]=dist[v]+e.cost;children[v].push_back(e.to);stack.push_back({e.to,0});}std::reverse(children[v].begin(),children[v].end());}else{subtree_size[v]=1;for(intchild:children[v])subtree_size[v]+=subtree_size[child];tout[v]=int(order.size());}}}intsize()const{return_n;}intvisited_size()const{returnint(order.size());}boolempty()const{return_n==0;}boolis_ancestor(intu,intv)const{check_vertex(u);check_vertex(v);returntin[u]<=tin[v]&&tout[v]<=tout[u];}boolin_subtree(intv,intu)const{returnis_ancestor(u,v);}std::pair<int,int>subtree_range(intv,booledge=false)const{check_vertex(v);return{tin[v]+(edge?1:0),tout[v]};}std::vector<int>subtree_vertices(intv)const{check_vertex(v);returnstd::vector<int>(order.begin()+tin[v],order.begin()+tout[v]);}template<classF>voidfor_each_subtree(intv,Ff)const{auto[l,r]=subtree_range(v);for(inti=l;i<r;++i)f(order[i]);}};}// namespace tree}// namespace m1une#line 1 "graph/tree/heavy_light_decomposition.hpp"
#line 8 "graph/tree/heavy_light_decomposition.hpp"
#line 10 "graph/tree/heavy_light_decomposition.hpp"
namespacem1une{namespacetree{structHldPathSegment{intl;intr;boolreversed;};template<classT=int>structHeavyLightDecomposition{usingcost_type=T;usingedge_type=m1une::graph::Edge<T>;introot;std::vector<int>parent;std::vector<int>parent_edge;std::vector<int>depth;std::vector<T>dist;std::vector<int>subtree_size;std::vector<int>heavy;std::vector<int>head;std::vector<int>tin;std::vector<int>tout;std::vector<int>order;private:int_n;voidcheck_vertex(intv)const{assert(0<=v&&v<_n);assert(tin[v]!=-1);}staticvoidadd_segment(std::vector<HldPathSegment>&result,intl,intr,boolreversed){if(l<r)result.push_back({l,r,reversed});}public:HeavyLightDecomposition():root(-1),_n(0){}explicitHeavyLightDecomposition(constm1une::graph::Graph<T>&g,introot_=0){build(g,root_);}voidbuild(constm1une::graph::Graph<T>&g,introot_=0){_n=g.size();root=_n==0?-1:root_;parent.assign(_n,-2);parent_edge.assign(_n,-1);depth.assign(_n,0);dist.assign(_n,T(0));subtree_size.assign(_n,1);heavy.assign(_n,-1);head.assign(_n,-1);tin.assign(_n,-1);tout.assign(_n,-1);order.clear();order.reserve(_n);if(_n==0)return;assert(0<=root&&root<_n);std::vector<int>dfs_order;dfs_order.reserve(_n);std::vector<int>stack={root};parent[root]=-1;while(!stack.empty()){intv=stack.back();stack.pop_back();dfs_order.push_back(v);for(constauto&e:g[v]){if(!e.alive)continue;if(parent[e.to]!=-2)continue;parent[e.to]=v;parent_edge[e.to]=e.id;depth[e.to]=depth[v]+1;dist[e.to]=dist[v]+e.cost;stack.push_back(e.to);}}for(inti=int(dfs_order.size())-1;i>=0;i--){intv=dfs_order[i];if(parent[v]==-1)continue;intp=parent[v];subtree_size[p]+=subtree_size[v];if(heavy[p]==-1||subtree_size[heavy[p]]<subtree_size[v])heavy[p]=v;}order.assign(dfs_order.size(),-1);inttimer=0;std::vector<std::pair<int,int>>starts={std::pair<int,int>{root,root}};while(!starts.empty()){auto[start,h]=starts.back();starts.pop_back();for(intv=start;v!=-1;v=heavy[v]){head[v]=h;tin[v]=timer;order[timer++]=v;for(autoit=g[v].rbegin();it!=g[v].rend();++it){if(!it->alive)continue;intto=it->to;if(parent[to]!=v||to==heavy[v])continue;starts.push_back({to,to});}}}for(inti=int(dfs_order.size())-1;i>=0;i--){intv=dfs_order[i];tout[v]=tin[v]+subtree_size[v];}}intsize()const{return_n;}boolempty()const{return_n==0;}boolis_ancestor(intu,intv)const{check_vertex(u);check_vertex(v);returntin[u]<=tin[v]&&tout[v]<=tout[u];}intlca(intu,intv)const{check_vertex(u);check_vertex(v);while(head[u]!=head[v]){if(depth[head[u]]<depth[head[v]])std::swap(u,v);u=parent[head[u]];}returndepth[u]<depth[v]?u:v;}intdist_edges(intu,intv)const{intw=lca(u,v);returndepth[u]+depth[v]-2*depth[w];}Tdist_cost(intu,intv)const{intw=lca(u,v);returndist[u]+dist[v]-dist[w]-dist[w];}intkth_ancestor(intv,intk)const{check_vertex(v);assert(0<=k);while(v!=-1){inth=head[v];intlen=depth[v]-depth[h];if(k<=len)returnorder[tin[v]-k];k-=len+1;v=parent[h];}return-1;}intjump(intfrom,intto,intk)const{check_vertex(from);check_vertex(to);assert(0<=k);intw=lca(from,to);intup_len=depth[from]-depth[w];intdown_len=depth[to]-depth[w];if(up_len+down_len<k)return-1;if(k<=up_len)returnkth_ancestor(from,k);returnkth_ancestor(to,down_len-(k-up_len));}std::pair<int,int>subtree_range(intv,booledge=false)const{check_vertex(v);return{tin[v]+(edge?1:0),tout[v]};}std::vector<HldPathSegment>path_segments(intu,intv,booledge=false)const{check_vertex(u);check_vertex(v);std::vector<HldPathSegment>result,down;while(head[u]!=head[v]){if(depth[head[u]]>=depth[head[v]]){add_segment(result,tin[head[u]],tin[u]+1,true);u=parent[head[u]];}else{add_segment(down,tin[head[v]],tin[v]+1,false);v=parent[head[v]];}}if(depth[u]>=depth[v]){add_segment(result,tin[v]+(edge?1:0),tin[u]+1,true);}else{add_segment(down,tin[u]+(edge?1:0),tin[v]+1,false);}std::reverse(down.begin(),down.end());result.insert(result.end(),down.begin(),down.end());returnresult;}template<classF>voidfor_each_path(intu,intv,Ff,booledge=false)const{for(autoseg:path_segments(u,v,edge))f(seg.l,seg.r,seg.reversed);}};}// namespace tree}// namespace m1une#line 1 "graph/tree/mo_on_tree.hpp"
#line 7 "graph/tree/mo_on_tree.hpp"
#line 1 "algo/offline/mo.hpp"
#line 6 "algo/offline/mo.hpp"
#include<cmath>
#line 9 "algo/offline/mo.hpp"
namespacem1une{namespacealgo{// Offline Mo's algorithm for half-open array ranges.structMo{structQuery{intleft;intright;intid;};private:int_n;std::vector<Query>_queries;public:Mo():_n(0){}explicitMo(intn):_n(n){assert(0<=n);}intsize()const{return_n;}intquery_count()const{returnint(_queries.size());}boolempty()const{return_queries.empty();}conststd::vector<Query>&queries()const{return_queries;}voidreserve(intquery_capacity){assert(0<=query_capacity);_queries.reserve(query_capacity);}voidclear(){_queries.clear();}// Adds [left, right) and returns its insertion-order ID.intadd_query(intleft,intright){assert(0<=left&&left<=right&&right<=_n);intid=query_count();_queries.push_back(Query{left,right,id});returnid;}// Returns query IDs in Mo order. A non-positive block size selects one// automatically.std::vector<int>order(intblock_size=0)const{intquery_size=query_count();std::vector<int>result(query_size);std::iota(result.begin(),result.end(),0);if(query_size==0)returnresult;if(block_size<=0){block_size=std::max(1,int(_n/std::sqrt(static_cast<double>(query_size))));}std::sort(result.begin(),result.end(),[&](intfirst,intsecond){constQuery&a=_queries[first];constQuery&b=_queries[second];intfirst_block=a.left/block_size;intsecond_block=b.left/block_size;if(first_block!=second_block){returnfirst_block<second_block;}if(first_block&1)returna.right>b.right;returna.right<b.right;});returnresult;}// Maintains [left, right). Each movement callback receives the array index// being inserted or erased. `answer(query_id)` stores or reports a result.template<classAddLeft,classAddRight,classRemoveLeft,classRemoveRight,classAnswer>voidrun(AddLeftadd_left,AddRightadd_right,RemoveLeftremove_left,RemoveRightremove_right,Answeranswer,intblock_size=0)const{intleft=0;intright=0;for(intquery_index:order(block_size)){constQuery&query=_queries[query_index];while(query.left<left)add_left(--left);while(right<query.right)add_right(right++);while(left<query.left)remove_left(left++);while(query.right<right)remove_right(--right);answer(query.id);}}// Convenience overload for statistics whose update is independent of// which side moves.template<classAdd,classRemove,classAnswer>voidrun(Addadd,Removeremove,Answeranswer,intblock_size=0)const{run(add,add,remove,remove,answer,block_size);}};}// namespace algo}// namespace m1une#line 11 "graph/tree/mo_on_tree.hpp"
namespacem1une{namespacetree{// Offline Mo's algorithm for static paths in a tree.template<classT=int>structMoOnTree{structQuery{intfrom;intto;intleft;intright;intextra;intid;booledge;};introot;std::vector<int>entry;std::vector<int>exit;std::vector<int>tour;private:int_n;HeavyLightDecomposition<T>_hld;m1une::algo::Mo_mo;std::vector<Query>_queries;voidcheck_vertex(intvertex)const{assert(0<=vertex&&vertex<_n);assert(entry[vertex]!=-1);}intadd_path_query(intfrom,intto,booledge){check_vertex(from);check_vertex(to);assert(_queries.empty()||_queries.front().edge==edge);intoriginal_from=from;intoriginal_to=to;if(entry[from]>entry[to])std::swap(from,to);intancestor=_hld.lca(from,to);intleft;intright=entry[to]+1;intextra=-1;if(ancestor==from){left=entry[from]+int(edge);}else{left=exit[from];if(!edge)extra=ancestor;}intid=_mo.add_query(left,right);_queries.push_back(Query{original_from,original_to,left,right,extra,id,edge,});returnid;}public:MoOnTree():root(-1),_n(0),_mo(0){}explicitMoOnTree(constm1une::graph::Graph<T>&graph,introot_vertex=0):root(-1),_n(0),_mo(0){build(graph,root_vertex);}voidbuild(constm1une::graph::Graph<T>&graph,introot_vertex=0){_n=graph.size();root=_n==0?-1:root_vertex;entry.assign(_n,-1);exit.assign(_n,-1);tour.clear();tour.reserve(2*_n);_queries.clear();_mo=m1une::algo::Mo(2*_n);_hld.build(graph,root_vertex);if(_n==0)return;assert(0<=root&&root<_n);for(intvertex=0;vertex<_n;++vertex){assert(_hld.parent[vertex]!=-2);}std::vector<std::vector<int>>children(_n);for(intvertex=0;vertex<_n;++vertex){intparent=_hld.parent[vertex];if(parent!=-1)children[parent].push_back(vertex);}structEvent{intvertex;boolleaving;};std::vector<Event>stack;stack.reserve(2*_n);stack.push_back(Event{root,false});while(!stack.empty()){Eventevent=stack.back();stack.pop_back();intvertex=event.vertex;if(event.leaving){exit[vertex]=int(tour.size());tour.push_back(vertex);continue;}entry[vertex]=int(tour.size());tour.push_back(vertex);stack.push_back(Event{vertex,true});constauto&child_list=children[vertex];for(intindex=int(child_list.size())-1;index>=0;--index){stack.push_back(Event{child_list[index],false});}}assert(int(tour.size())==2*_n);}intsize()const{return_n;}boolempty()const{return_n==0;}intquery_count()const{returnint(_queries.size());}conststd::vector<Query>&queries()const{return_queries;}intparent(intvertex)const{check_vertex(vertex);return_hld.parent[vertex];}intparent_edge(intvertex)const{check_vertex(vertex);return_hld.parent_edge[vertex];}intdepth(intvertex)const{check_vertex(vertex);return_hld.depth[vertex];}intlca(intfirst,intsecond)const{check_vertex(first);check_vertex(second);return_hld.lca(first,second);}voidreserve(intquery_capacity){assert(0<=query_capacity);_queries.reserve(query_capacity);_mo.reserve(query_capacity);}voidclear(){_queries.clear();_mo.clear();}// Adds an inclusive vertex-path query and returns its insertion-order ID.// Vertex and edge queries cannot be mixed in one collection.intadd_query(intfrom,intto){returnadd_path_query(from,to,false);}// Adds an edge-path query. Each edge is represented by its child vertex.intadd_edge_query(intfrom,intto){returnadd_path_query(from,to,true);}std::vector<int>order(intblock_size=0)const{return_mo.order(block_size);}// `add(v)` and `remove(v)` maintain the current path. In edge mode, v// always represents the real edge parent_edge(v).template<classAdd,classRemove,classAnswer>voidrun(Addadd,Removeremove,Answeranswer,intblock_size=0)const{booledge_mode=!_queries.empty()&&_queries.front().edge;std::vector<char>active(_n,false);autotoggle=[&](inttour_index){intvertex=tour[tour_index];if(!edge_mode||vertex!=root){if(active[vertex]){remove(vertex);}else{add(vertex);}}active[vertex]=!active[vertex];};_mo.run(toggle,toggle,[&](intquery_id){intextra=_queries[query_id].extra;if(extra!=-1){assert(!active[extra]);add(extra);}answer(query_id);if(extra!=-1)remove(extra);},block_size);}};}// namespace tree}// namespace m1une#line 1 "graph/tree/range_contour_query.hpp"
#line 7 "graph/tree/range_contour_query.hpp"
#line 1 "graph/tree/rooted_tree.hpp"
#line 7 "graph/tree/rooted_tree.hpp"
#line 9 "graph/tree/rooted_tree.hpp"
namespacem1une{namespacetree{template<classT=int>structRootedTree{usingcost_type=T;usingedge_type=m1une::graph::Edge<T>;introot;std::vector<int>parent;std::vector<int>parent_edge;std::vector<int>depth;std::vector<T>dist;std::vector<int>subtree_size;std::vector<int>tin;std::vector<int>tout;std::vector<int>order;std::vector<std::vector<int>>up;private:int_n;int_log;voidcheck_vertex(intv)const{assert(0<=v&&v<_n);assert(tin[v]!=-1);}public:RootedTree():root(-1),_n(0),_log(0){}explicitRootedTree(constm1une::graph::Graph<T>&g,introot_=0){build(g,root_);}voidbuild(constm1une::graph::Graph<T>&g,introot_=0){_n=g.size();root=_n==0?-1:root_;_log=1;while((1U<<_log)<=(unsignedint)(std::max(1,_n)))_log++;parent.assign(_n,-1);parent_edge.assign(_n,-1);depth.assign(_n,0);dist.assign(_n,T(0));subtree_size.assign(_n,0);tin.assign(_n,-1);tout.assign(_n,-1);order.clear();order.reserve(_n);up.assign(_log,std::vector<int>(_n,-1));if(_n==0)return;assert(0<=root&&root<_n);structFrame{intv;intstate;};std::vector<char>visited(_n,false);std::vector<Frame>stack;stack.push_back({root,0});visited[root]=true;inttimer=0;while(!stack.empty()){Frameframe=stack.back();stack.pop_back();intv=frame.v;if(frame.state==0){tin[v]=timer++;order.push_back(v);up[0][v]=parent[v];for(intk=1;k<_log;k++){intp=up[k-1][v];up[k][v]=p==-1?-1:up[k-1][p];}stack.push_back({v,1});constauto&adj=g[v];for(inti=int(adj.size())-1;i>=0;i--){constauto&e=adj[i];if(!e.alive)continue;if(visited[e.to])continue;visited[e.to]=true;parent[e.to]=v;parent_edge[e.to]=e.id;depth[e.to]=depth[v]+1;dist[e.to]=dist[v]+e.cost;stack.push_back({e.to,0});}}else{subtree_size[v]++;if(parent[v]!=-1)subtree_size[parent[v]]+=subtree_size[v];tout[v]=timer;}}}intsize()const{return_n;}boolempty()const{return_n==0;}intlog()const{return_log;}boolis_ancestor(intu,intv)const{check_vertex(u);check_vertex(v);returntin[u]<=tin[v]&&tout[v]<=tout[u];}boolin_subtree(intv,intu)const{returnis_ancestor(u,v);}intkth_ancestor(intv,intk)const{check_vertex(v);assert(0<=k);intbit=0;while(k>0&&v!=-1){if(k&1){if(_log<=bit)return-1;v=up[bit][v];}k>>=1;bit++;}returnv;}intlca(intu,intv)const{check_vertex(u);check_vertex(v);if(depth[u]<depth[v])std::swap(u,v);u=kth_ancestor(u,depth[u]-depth[v]);if(u==v)returnu;for(intk=_log-1;k>=0;k--){if(up[k][u]!=up[k][v]){u=up[k][u];v=up[k][v];}}returnparent[u];}intdist_edges(intu,intv)const{intw=lca(u,v);returndepth[u]+depth[v]-2*depth[w];}Tdist_cost(intu,intv)const{intw=lca(u,v);returndist[u]+dist[v]-dist[w]-dist[w];}intjump(intfrom,intto,intk)const{check_vertex(from);check_vertex(to);assert(0<=k);intw=lca(from,to);intup_len=depth[from]-depth[w];intdown_len=depth[to]-depth[w];if(up_len+down_len<k)return-1;if(k<=up_len)returnkth_ancestor(from,k);returnkth_ancestor(to,down_len-(k-up_len));}std::vector<int>path(intu,intv)const{check_vertex(u);check_vertex(v);intw=lca(u,v);std::vector<int>a,b;for(intx=u;x!=w;x=parent[x])a.push_back(x);a.push_back(w);for(intx=v;x!=w;x=parent[x])b.push_back(x);std::reverse(b.begin(),b.end());a.insert(a.end(),b.begin(),b.end());returna;}std::vector<int>path_edges(intu,intv)const{check_vertex(u);check_vertex(v);intw=lca(u,v);std::vector<int>a,b;for(intx=u;x!=w;x=parent[x])a.push_back(parent_edge[x]);for(intx=v;x!=w;x=parent[x])b.push_back(parent_edge[x]);std::reverse(b.begin(),b.end());a.insert(a.end(),b.begin(),b.end());returna;}std::pair<int,int>subtree_range(intv)const{check_vertex(v);return{tin[v],tout[v]};}std::vector<int>subtree_vertices(intv)const{check_vertex(v);returnstd::vector<int>(order.begin()+tin[v],order.begin()+tout[v]);}};}// namespace tree}// namespace m1une#line 13 "graph/tree/range_contour_query.hpp"
namespacem1une{namespacetree{namespaceinternal{structRangeContourPathEntry{intcentroid;intdistance;intsubtree;};structRangeContourLayout{intn=0;std::vector<std::vector<RangeContourPathEntry>>path;std::vector<int>all_size;std::vector<int>subtree_size;template<classEdgeCost>voidbuild(constm1une::graph::Graph<EdgeCost>&graph){n=graph.size();path.assign(n,{});all_size.assign(n,0);subtree_size.assign(n,0);if(n==0)return;#ifndef NDEBUG
std::vector<int>incidence(graph.edge_count(),0);for(intvertex=0;vertex<n;vertex++){for(constauto&edge:graph[vertex]){if(!edge.alive)continue;assert(0<=edge.id&&edge.id<graph.edge_count());incidence[edge.id]++;}}intactive_edges=0;for(intcount:incidence){if(count==0)continue;assert(count==2);active_edges++;}assert(active_edges==n-1);#endif
RootedTree<EdgeCost>rooted(graph,0);assert(int(rooted.order.size())==n);CentroidDecomposition<EdgeCost>decomposition(graph);for(intvertex=0;vertex<n;vertex++){intprevious=-1;for(intcentroid=vertex;centroid!=-1;centroid=decomposition.parent[centroid]){intdistance=rooted.dist_edges(vertex,centroid);path[vertex].push_back(RangeContourPathEntry{centroid,distance,previous});all_size[centroid]=std::max(all_size[centroid],distance+1);if(previous!=-1){subtree_size[previous]=std::max(subtree_size[previous],distance+1);}previous=centroid;}}}};template<m1une::monoid::IsCommutativeGroupGroup>classRangeContourFenwick{public:usingT=typenameGroup::value_type;private:int_n=0;std::vector<T>_data;Tprefix_product(intright)const{Tresult=Group::id();while(right>0){result=Group::op(result,_data[right]);right-=right&-right;}returnresult;}public:RangeContourFenwick():_data(1,Group::id()){}explicitRangeContourFenwick(intn):_n(n),_data(n+1,Group::id()){assert(0<=n);}intsize()const{return_n;}voidapply(intindex,constT&value){assert(0<=index&&index<_n);for(index++;index<=_n;index+=index&-index){_data[index]=Group::op(_data[index],value);}}Tproduct(intleft,intright)const{left=std::max(left,0);right=std::min(right,_n);if(right<=left)returnGroup::id();returnGroup::op(Group::inv(prefix_product(left)),prefix_product(right));}voidrange_apply(intleft,intright,constT&value){left=std::max(left,0);right=std::min(right,_n);if(right<=left)return;apply(left,value);if(right<_n)apply(right,Group::inv(value));}Tget(intindex)const{assert(0<=index&&index<_n);returnprefix_product(index+1);}};}// namespace internaltemplate<m1une::monoid::IsCommutativeGroupGroup>classVertexApplyRangeContourProduct{public:usingT=typenameGroup::value_type;private:internal::RangeContourLayout_layout;std::vector<T>_value;std::vector<internal::RangeContourFenwick<Group>>_all;std::vector<internal::RangeContourFenwick<Group>>_subtree;voidcheck_vertex(intvertex)const{assert(0<=vertex&&vertex<size());}public:VertexApplyRangeContourProduct()=default;template<classEdgeCost>explicitVertexApplyRangeContourProduct(constm1une::graph::Graph<EdgeCost>&graph,conststd::vector<T>&initial={}){build(graph,initial);}template<classEdgeCost>voidbuild(constm1une::graph::Graph<EdgeCost>&graph,conststd::vector<T>&initial={}){assert(initial.empty()||int(initial.size())==graph.size());_layout.build(graph);constintn=_layout.n;_value.assign(n,Group::id());_all.assign(n,internal::RangeContourFenwick<Group>());_subtree.assign(n,internal::RangeContourFenwick<Group>());for(intindex=0;index<n;index++){_all[index]=internal::RangeContourFenwick<Group>(_layout.all_size[index]);_subtree[index]=internal::RangeContourFenwick<Group>(_layout.subtree_size[index]);}if(!initial.empty()){for(intvertex=0;vertex<n;vertex++){apply(vertex,initial[vertex]);}}}intsize()const{return_layout.n;}boolempty()const{returnsize()==0;}Tget(intvertex)const{check_vertex(vertex);return_value[vertex];}voidapply(intvertex,constT&value){check_vertex(vertex);_value[vertex]=Group::op(_value[vertex],value);for(constauto&entry:_layout.path[vertex]){_all[entry.centroid].apply(entry.distance,value);if(entry.subtree!=-1){_subtree[entry.subtree].apply(entry.distance,value);}}}voidset(intvertex,constT&value){check_vertex(vertex);apply(vertex,Group::op(Group::inv(_value[vertex]),value));}Tprod(intvertex,intleft_distance,intright_distance)const{check_vertex(vertex);assert(0<=left_distance&&left_distance<=right_distance);Tresult=Group::id();for(constauto&entry:_layout.path[vertex]){intleft=left_distance-entry.distance;intright=right_distance-entry.distance;result=Group::op(result,_all[entry.centroid].product(left,right));if(entry.subtree!=-1){result=Group::op(result,Group::inv(_subtree[entry.subtree].product(left,right)));}}returnresult;}};template<m1une::monoid::IsCommutativeGroupGroup>classVertexGetRangeContourApply{public:usingT=typenameGroup::value_type;private:internal::RangeContourLayout_layout;std::vector<T>_base;std::vector<internal::RangeContourFenwick<Group>>_all;std::vector<internal::RangeContourFenwick<Group>>_subtree;voidcheck_vertex(intvertex)const{assert(0<=vertex&&vertex<size());}public:VertexGetRangeContourApply()=default;template<classEdgeCost>explicitVertexGetRangeContourApply(constm1une::graph::Graph<EdgeCost>&graph,conststd::vector<T>&initial={}){build(graph,initial);}template<classEdgeCost>voidbuild(constm1une::graph::Graph<EdgeCost>&graph,conststd::vector<T>&initial={}){assert(initial.empty()||int(initial.size())==graph.size());_layout.build(graph);constintn=_layout.n;_base=initial.empty()?std::vector<T>(n,Group::id()):initial;_all.assign(n,internal::RangeContourFenwick<Group>());_subtree.assign(n,internal::RangeContourFenwick<Group>());for(intindex=0;index<n;index++){_all[index]=internal::RangeContourFenwick<Group>(_layout.all_size[index]);_subtree[index]=internal::RangeContourFenwick<Group>(_layout.subtree_size[index]);}}intsize()const{return_layout.n;}boolempty()const{returnsize()==0;}Tget(intvertex)const{check_vertex(vertex);Tresult=_base[vertex];for(constauto&entry:_layout.path[vertex]){result=Group::op(result,_all[entry.centroid].get(entry.distance));if(entry.subtree!=-1){result=Group::op(result,Group::inv(_subtree[entry.subtree].get(entry.distance)));}}returnresult;}voidpoint_apply(intvertex,constT&value){check_vertex(vertex);_base[vertex]=Group::op(_base[vertex],value);}voidset(intvertex,constT&value){check_vertex(vertex);_base[vertex]=Group::op(_base[vertex],Group::op(Group::inv(get(vertex)),value));}voidapply(intvertex,intleft_distance,intright_distance,constT&value){check_vertex(vertex);assert(0<=left_distance&&left_distance<=right_distance);for(constauto&entry:_layout.path[vertex]){intleft=left_distance-entry.distance;intright=right_distance-entry.distance;_all[entry.centroid].range_apply(left,right,value);if(entry.subtree!=-1){_subtree[entry.subtree].range_apply(left,right,value);}}}};template<classT>classVertexAddRangeContourSum:publicVertexApplyRangeContourProduct<m1une::monoid::Add<T>>{private:usingBase=VertexApplyRangeContourProduct<m1une::monoid::Add<T>>;public:usingBase::Base;voidadd(intvertex,constT&delta){Base::apply(vertex,delta);}Tsum(intvertex,intleft_distance,intright_distance)const{returnBase::prod(vertex,left_distance,right_distance);}};template<classT>classVertexGetRangeContourAdd:publicVertexGetRangeContourApply<m1une::monoid::Add<T>>{private:usingBase=VertexGetRangeContourApply<m1une::monoid::Add<T>>;public:usingBase::Base;voidadd(intvertex,constT&delta){Base::point_apply(vertex,delta);}};}// namespace tree}// namespace m1une#line 1 "graph/tree/rerooting_dp.hpp"
#line 5 "graph/tree/rerooting_dp.hpp"
#line 7 "graph/tree/rerooting_dp.hpp"
namespacem1une{namespacetree{template<classT,classDP,classMerge,classAddVertex,classAddEdge>std::vector<DP>rerooting_dp(constm1une::graph::Graph<T>&g,DPid,Mergemerge,AddVertexadd_vertex,AddEdgeadd_edge){intn=g.size();std::vector<int>parent(n,-2),parent_edge(n,-1),order;order.reserve(n);for(introot=0;root<n;root++){if(parent[root]!=-2)continue;parent[root]=-1;std::vector<int>stack={root};while(!stack.empty()){intv=stack.back();stack.pop_back();order.push_back(v);for(constauto&e:g[v]){if(!e.alive)continue;if(parent[e.to]!=-2)continue;parent[e.to]=v;parent_edge[e.to]=e.id;stack.push_back(e.to);}}}std::vector<DP>down(n,id),outside(n,id),answer(n,id);for(inti=n-1;i>=0;i--){intv=order[i];DPacc=id;for(constauto&e:g[v]){if(!e.alive)continue;if(parent[e.to]!=v)continue;acc=merge(acc,add_edge(down[e.to],e));}down[v]=add_vertex(acc,v);}for(intv:order){intd=int(g[v].size());std::vector<DP>contrib(d,id);for(inti=0;i<d;i++){constauto&e=g[v][i];if(!e.alive)continue;if(parent[e.to]==v){contrib[i]=add_edge(down[e.to],e);}elseif(parent[v]==e.to&&parent_edge[v]==e.id){contrib[i]=add_edge(outside[v],e);}}std::vector<DP>pref(d+1,id),suff(d+1,id);for(inti=0;i<d;i++)pref[i+1]=merge(pref[i],contrib[i]);for(inti=d-1;i>=0;i--)suff[i]=merge(contrib[i],suff[i+1]);answer[v]=add_vertex(pref[d],v);for(inti=0;i<d;i++){constauto&e=g[v][i];if(!e.alive)continue;if(parent[e.to]!=v)continue;outside[e.to]=add_vertex(merge(pref[i],suff[i+1]),v);}}returnanswer;}}// namespace tree}// namespace m1une#line 1 "graph/tree/rerooting_static_top_tree.hpp"
#line 6 "graph/tree/rerooting_static_top_tree.hpp"
#include<optional>
#line 10 "graph/tree/rerooting_static_top_tree.hpp"
#line 12 "graph/tree/rerooting_static_top_tree.hpp"
namespacem1une{namespacetree{namespaceinternal{enumclassRerootingStaticTopTreeNodeType{Compress,Rake,AddEdge,AddVertex,};enumclassRerootingStaticTopTreeStepType{CompressLower,CompressUpper,AddEdge,RakeLeft,RakeRight,AddVertex,};}// namespace internaltemplate<classT,classVertex,classPath,classPoint,classCompressDown,classCompressUp,classRake,classAddEdgeDown,classAddEdgeUp,classAddVertex>structRerootingStaticTopTree{usingcost_type=T;usingvertex_type=Vertex;usingpath_type=Path;usingpoint_type=Point;usingedge_type=m1une::graph::Edge<T>;usingnode_type=internal::RerootingStaticTopTreeNodeType;usingstep_type=internal::RerootingStaticTopTreeStepType;structNode{node_typetype;intleft=-1;intright=-1;intparent=-1;intvertex=-1;edge_typeedge;intsize=0;intheight=1;std::optional<Path>path_down;std::optional<Path>path_up;std::optional<Point>point;};structRerootingStep{step_typetype;intnode=-1;intsibling=-1;intvertex=-1;edge_typeedge;};private:int_n;int_root;int_root_node;Point_point_id;CompressDown_compress_down;CompressUp_compress_up;Rake_rake;AddEdgeDown_add_edge_down;AddEdgeUp_add_edge_up;AddVertex_add_vertex;std::vector<Vertex>_values;std::vector<Node>_nodes;std::vector<int>_vertex_node;std::vector<int>_edge_node;std::vector<int>_parent;std::vector<int>_subtree_size;std::vector<int>_heavy;std::vector<edge_type>_heavy_edge;std::vector<std::vector<edge_type>>_children;staticedge_typereversed_edge(edge_typee){std::swap(e.from,e.to);returne;}constPath&node_path_down(intnode)const{assert(0<=node&&node<int(_nodes.size()));assert(_nodes[node].path_down.has_value());return*_nodes[node].path_down;}constPath&node_path_up(intnode)const{assert(0<=node&&node<int(_nodes.size()));assert(_nodes[node].path_up.has_value());return*_nodes[node].path_up;}constPoint&node_point(intnode)const{assert(0<=node&&node<int(_nodes.size()));assert(_nodes[node].point.has_value());return*_nodes[node].point;}voidset_parent(intchild,intparent){if(child!=-1)_nodes[child].parent=parent;}voidrecompute(intnode){auto&x=_nodes[node];if(x.type==node_type::Compress){x.path_down=_compress_down(node_path_down(x.left),node_path_down(x.right),x.edge);x.path_up=_compress_up(node_path_up(x.right),node_path_up(x.left),reversed_edge(x.edge));}elseif(x.type==node_type::Rake){x.point=_rake(node_point(x.left),node_point(x.right));}elseif(x.type==node_type::AddEdge){x.point=_add_edge_down(node_path_down(x.left),x.edge);}else{constPoint&side=x.left==-1?_point_id:node_point(x.left);Pathpath=_add_vertex(side,_values[x.vertex],x.vertex);x.path_down=path;x.path_up=std::move(path);}}intnew_node(Nodenode){intid=int(_nodes.size());_nodes.push_back(std::move(node));set_parent(_nodes[id].left,id);set_parent(_nodes[id].right,id);recompute(id);returnid;}intnew_compress(intleft,intright,edge_typeedge){Nodenode;node.type=node_type::Compress;node.left=left;node.right=right;node.edge=edge;node.size=_nodes[left].size+_nodes[right].size;node.height=std::max(_nodes[left].height,_nodes[right].height)+1;intid=new_node(std::move(node));if(0<=edge.id&&edge.id<int(_edge_node.size()))_edge_node[edge.id]=id;returnid;}intnew_rake(intleft,intright){Nodenode;node.type=node_type::Rake;node.left=left;node.right=right;node.size=_nodes[left].size+_nodes[right].size;node.height=std::max(_nodes[left].height,_nodes[right].height)+1;returnnew_node(std::move(node));}intnew_add_edge(intchild,edge_typeedge){Nodenode;node.type=node_type::AddEdge;node.left=child;node.edge=edge;node.size=_nodes[child].size;node.height=_nodes[child].height+1;intid=new_node(std::move(node));if(0<=edge.id&&edge.id<int(_edge_node.size()))_edge_node[edge.id]=id;returnid;}intnew_add_vertex(intside,intvertex){Nodenode;node.type=node_type::AddVertex;node.left=side;node.vertex=vertex;node.size=1+(side==-1?0:_nodes[side].size);node.height=1+(side==-1?0:_nodes[side].height);intid=new_node(std::move(node));_vertex_node[vertex]=id;returnid;}intweighted_split(conststd::vector<int>&nodes,intl,intr)const{inttotal=0;for(inti=l;i<r;i++)total+=_nodes[nodes[i]].size;intleft_sum=0;for(inti=l;i+1<r;i++){left_sum+=_nodes[nodes[i]].size;if(2*left_sum>=total)returni+1;}returnr-1;}intbuild_rake(conststd::vector<int>&nodes,intl,intr){if(l==r)return-1;if(l+1==r)returnnodes[l];intm=weighted_split(nodes,l,r);returnnew_rake(build_rake(nodes,l,m),build_rake(nodes,m,r));}intbuild_compress(conststd::vector<int>&nodes,conststd::vector<edge_type>&edges,intl,intr){if(l+1==r)returnnodes[l];intm=weighted_split(nodes,l,r);returnnew_compress(build_compress(nodes,edges,l,m),build_compress(nodes,edges,m,r),edges[m-1]);}intbuild_vertex(intv){std::vector<int>side_nodes;for(constauto&e:_children[v]){if(e.to==_heavy[v])continue;intchild_path=build_path(e.to);side_nodes.push_back(new_add_edge(child_path,e));}returnnew_add_vertex(build_rake(side_nodes,0,int(side_nodes.size())),v);}intbuild_path(intstart){std::vector<int>path_nodes;std::vector<edge_type>path_edges;for(intv=start;v!=-1;v=_heavy[v]){path_nodes.push_back(build_vertex(v));if(_heavy[v]!=-1)path_edges.push_back(_heavy_edge[v]);}returnbuild_compress(path_nodes,path_edges,0,int(path_nodes.size()));}voidrecompute_up(intnode){while(node!=-1){recompute(node);node=_nodes[node].parent;}}public:RerootingStaticTopTree(constm1une::graph::Graph<T>&g,conststd::vector<Vertex>&values,Pointpoint_id,CompressDowncompress_down,CompressUpcompress_up,Rakerake,AddEdgeDownadd_edge_down,AddEdgeUpadd_edge_up,AddVertexadd_vertex,introot=0):_n(g.size()),_root(_n==0?-1:root),_root_node(-1),_point_id(std::move(point_id)),_compress_down(std::move(compress_down)),_compress_up(std::move(compress_up)),_rake(std::move(rake)),_add_edge_down(std::move(add_edge_down)),_add_edge_up(std::move(add_edge_up)),_add_vertex(std::move(add_vertex)),_values(values){build(g,root);}voidbuild(constm1une::graph::Graph<T>&g,introot=0){_n=g.size();_root=_n==0?-1:root;assert(int(_values.size())==_n);_nodes.clear();_vertex_node.assign(_n,-1);_edge_node.assign(g.edge_count(),-1);_parent.assign(_n,-2);_subtree_size.assign(_n,1);_heavy.assign(_n,-1);_heavy_edge.assign(_n,edge_type());_children.assign(_n,{});_root_node=-1;if(_n==0)return;assert(0<=root&&root<_n);assert(int(g.edges().size())==_n-1);std::vector<int>order;order.reserve(_n);std::vector<int>stack={root};_parent[root]=-1;while(!stack.empty()){intv=stack.back();stack.pop_back();order.push_back(v);for(constauto&e:g[v]){if(!e.alive)continue;if(_parent[e.to]!=-2)continue;_parent[e.to]=v;_children[v].push_back(e);stack.push_back(e.to);}}assert(int(order.size())==_n);for(inti=int(order.size())-1;i>=0;i--){intv=order[i];for(constauto&e:_children[v]){_subtree_size[v]+=_subtree_size[e.to];if(_heavy[v]==-1||_subtree_size[_heavy[v]]<_subtree_size[e.to]){_heavy[v]=e.to;_heavy_edge[v]=e;}}}_root_node=build_path(root);}intsize()const{return_n;}boolempty()const{return_n==0;}introot()const{return_root;}introot_node()const{return_root_node;}intnode_count()const{returnint(_nodes.size());}intheight()const{return_root_node==-1?0:_nodes[_root_node].height;}conststd::vector<Node>&nodes()const{return_nodes;}constNode&node(intid)const{assert(0<=id&&id<int(_nodes.size()));return_nodes[id];}intparent_node(intid)const{returnnode(id).parent;}intvertex_node(intv)const{assert(0<=v&&v<_n);return_vertex_node[v];}intlocal_point_node(intv)const{intid=vertex_node(v);assert(_nodes[id].type==node_type::AddVertex);return_nodes[id].left;}constPoint&local_point(intv)const{intpoint_node=local_point_node(v);returnpoint_node==-1?_point_id:node_point(point_node);}constVertex&get(intv)const{assert(0<=v&&v<_n);return_values[v];}constVertex&operator[](intv)const{returnget(v);}voidset(intv,constVertex&value){assert(0<=v&&v<_n);assert(_vertex_node[v]!=-1);_values[v]=value;recompute_up(_vertex_node[v]);}voidset(intv,Vertex&&value){assert(0<=v&&v<_n);assert(_vertex_node[v]!=-1);_values[v]=std::move(value);recompute_up(_vertex_node[v]);}voidset_edge_cost(intedge_id,Tcost){assert(0<=edge_id&&edge_id<int(_edge_node.size()));intnode=_edge_node[edge_id];assert(node!=-1);_nodes[node].edge.cost=cost;recompute_up(node);}constPath&path_down(intnode_id)const{returnnode_path_down(node_id);}constPath&path_up(intnode_id)const{returnnode_path_up(node_id);}constPoint&point(intnode_id)const{returnnode_point(node_id);}constPath&all_prod_down()const{assert(_root_node!=-1);returnpath_down(_root_node);}constPath&all_prod_up()const{assert(_root_node!=-1);returnpath_up(_root_node);}constPoint&point_id()const{return_point_id;}template<classF>voidfor_each_rerooting_step(intv,F&&f)const{assert(0<=v&&v<_n);intcur=_vertex_node[v];assert(cur!=-1);while(_nodes[cur].parent!=-1){intpar=_nodes[cur].parent;constauto&p=_nodes[par];RerootingStepstep;step.node=par;if(p.type==node_type::Compress){step.edge=p.edge;if(p.left==cur){step.type=step_type::CompressLower;step.sibling=p.right;}else{assert(p.right==cur);step.type=step_type::CompressUpper;step.sibling=p.left;}}elseif(p.type==node_type::Rake){if(p.left==cur){step.type=step_type::RakeRight;step.sibling=p.right;}else{assert(p.right==cur);step.type=step_type::RakeLeft;step.sibling=p.left;}}elseif(p.type==node_type::AddEdge){assert(p.left==cur);step.type=step_type::AddEdge;step.edge=p.edge;}else{assert(p.type==node_type::AddVertex);assert(p.left==cur);step.type=step_type::AddVertex;step.vertex=p.vertex;}f(step);cur=par;}}std::vector<RerootingStep>rerooting_steps(intv)const{std::vector<RerootingStep>result;intcur=vertex_node(v);intdepth=0;while(_nodes[cur].parent!=-1){cur=_nodes[cur].parent;depth++;}result.reserve(depth);for_each_rerooting_step(v,[&](constRerootingStep&step){result.push_back(step);});returnresult;}template<classFolder>autofold_rerooting(intv,Folderfolder)const{folder.start(v,_values[v],local_point(v));for_each_rerooting_step(v,[&](constRerootingStep&step){if(step.type==step_type::CompressLower){folder.compress_lower(path_down(step.sibling),step.edge);}elseif(step.type==step_type::CompressUpper){folder.compress_upper(path_up(step.sibling),reversed_edge(step.edge));}elseif(step.type==step_type::AddEdge){folder.add_edge(reversed_edge(step.edge));}elseif(step.type==step_type::RakeLeft){folder.rake_left(point(step.sibling));}elseif(step.type==step_type::RakeRight){folder.rake_right(point(step.sibling));}else{folder.add_vertex(step.vertex,_values[step.vertex]);}});returnfolder.result();}Pathcompress_down(constPath&upper,constPath&lower,edge_typeedge)const{return_compress_down(upper,lower,edge);}Pathcompress_up(constPath&lower,constPath&upper,edge_typeedge)const{return_compress_up(lower,upper,edge);}Pointrake(constPoint&left,constPoint&right)const{return_rake(left,right);}Pointadd_edge_down(constPath&path,edge_typeedge)const{return_add_edge_down(path,edge);}Pointadd_edge_up(constPath&path,edge_typeedge)const{return_add_edge_up(path,edge);}Pathadd_vertex(constPoint&side,constVertex&value,intvertex)const{return_add_vertex(side,value,vertex);}staticedge_typereverse_edge(edge_typeedge){returnreversed_edge(edge);}};template<classT,classVertex,classPoint,classCompressDown,classCompressUp,classRake,classAddEdgeDown,classAddEdgeUp,classAddVertex>RerootingStaticTopTree(constm1une::graph::Graph<T>&,conststd::vector<Vertex>&,Point,CompressDown,CompressUp,Rake,AddEdgeDown,AddEdgeUp,AddVertex,int)->RerootingStaticTopTree<T,Vertex,std::invoke_result_t<AddVertex,Point,Vertex,int>,Point,CompressDown,CompressUp,Rake,AddEdgeDown,AddEdgeUp,AddVertex>;template<classT,classVertex,classPoint,classCompressDown,classCompressUp,classRake,classAddEdgeDown,classAddEdgeUp,classAddVertex>RerootingStaticTopTree(constm1une::graph::Graph<T>&,conststd::vector<Vertex>&,Point,CompressDown,CompressUp,Rake,AddEdgeDown,AddEdgeUp,AddVertex)->RerootingStaticTopTree<T,Vertex,std::invoke_result_t<AddVertex,Point,Vertex,int>,Point,CompressDown,CompressUp,Rake,AddEdgeDown,AddEdgeUp,AddVertex>;}// namespace tree}// namespace m1une#line 1 "graph/tree/sparse_table_lca.hpp"
#line 9 "graph/tree/sparse_table_lca.hpp"
#line 1 "ds/range_query/sparse_table.hpp"
#include<bit>
#line 9 "ds/range_query/sparse_table.hpp"
#line 11 "ds/range_query/sparse_table.hpp"
namespacem1une{namespaceds{// A Sparse Table utilizing C++20 Concepts for type safety.// It requires a Monoid struct that satisfies `m1une::monoid::IsMonoid`.// [IMPORTANT] For O(1) range queries to work correctly, the monoid operation MUST be idempotent.// i.e., Monoid::op(x, x) == x must hold (e.g., Min, Max, GCD, Bitwise AND/OR).template<m1une::monoid::IsMonoidMonoid>structSparseTable{usingT=typenameMonoid::value_type;private:int_n;std::vector<std::vector<T>>_st;public:// Constructs an empty sparse table.SparseTable():_n(0){}// Constructs a sparse table from an existing vector in O(N log N) time.explicitSparseTable(conststd::vector<T>&v):_n(int(v.size())){if(_n==0)return;// Compute the maximum power of 2 neededintmax_log=std::bit_width((unsignedint)_n);_st.assign(max_log,std::vector<T>(_n));// Initialize the base levelfor(inti=0;i<_n;i++){_st[0][i]=v[i];}// Build the sparse tablefor(intk=1;k<max_log;k++){for(inti=0;i+(1<<k)<=_n;i++){_st[k][i]=Monoid::op(_st[k-1][i],_st[k-1][i+(1<<(k-1))]);}}}explicitSparseTable(std::vector<T>&&v):_n(int(v.size())){if(_n==0)return;intmax_log=std::bit_width((unsignedint)_n);_st.assign(max_log,std::vector<T>(_n));for(inti=0;i<_n;i++){_st[0][i]=std::move(v[i]);}for(intk=1;k<max_log;k++){for(inti=0;i+(1<<k)<=_n;i++){_st[k][i]=Monoid::op(_st[k-1][i],_st[k-1][i+(1<<(k-1))]);}}}// Constructs a sparse table from a vector of a different type U.// It automatically adapts to the Monoid's initialization requirements:// 1. Monoid::make(val) if it exists.// 2. Monoid::make(val, index) if the monoid requires global indices.// 3. static_cast<T>(val) as a fallback for simple monoids.template<typenameU>requires(!std::same_as<U,T>)&&(requires(Ux){Monoid::make(x);}||requires(Ux,inti){Monoid::make(x,i);}||std::convertible_to<U,T>)explicitSparseTable(conststd::vector<U>&v):_n(int(v.size())){if(_n==0)return;intmax_log=std::bit_width((unsignedint)_n);_st.assign(max_log,std::vector<T>(_n));// Compile-time branching based on the available make() signaturefor(inti=0;i<_n;i++){ifconstexpr(requires(Ux){Monoid::make(x);}){_st[0][i]=Monoid::make(v[i]);}elseifconstexpr(requires(Ux,intidx){Monoid::make(x,idx);}){_st[0][i]=Monoid::make(v[i],i);}else{_st[0][i]=static_cast<T>(v[i]);}}for(intk=1;k<max_log;k++){for(inti=0;i+(1<<k)<=_n;i++){_st[k][i]=Monoid::op(_st[k-1][i],_st[k-1][i+(1<<(k-1))]);}}}// Returns the product (result of the monoid operation) in the range [l, r) in O(1) time.// Requires the monoid operation to be idempotent.Tprod(intl,intr)const{assert(0<=l&&l<=r&&r<=_n);if(l==r)returnMonoid::id();// Calculate the largest power of 2 less than or equal to the interval lengthintk=std::bit_width((unsignedint)(r-l))-1;returnMonoid::op(_st[k][l],_st[k][r-(1<<k)]);}};}// namespace ds}// namespace m1une#line 12 "graph/tree/sparse_table_lca.hpp"
namespacem1une{namespacetree{template<classT=int>structSparseTableLca{usingcost_type=T;usingedge_type=m1une::graph::Edge<T>;introot;std::vector<int>parent;std::vector<int>parent_edge;std::vector<int>depth;std::vector<T>dist;std::vector<int>subtree_size;std::vector<int>tin;std::vector<int>tout;std::vector<int>order;std::vector<int>first;std::vector<int>euler;private:structRmqNode{intdepth;intvertex;};structRmqMonoid{usingvalue_type=RmqNode;staticvalue_typeid(){return{std::numeric_limits<int>::max(),-1};}staticvalue_typeop(constvalue_type&a,constvalue_type&b){if(a.depth!=b.depth)returna.depth<b.depth?a:b;returna.vertex<b.vertex?a:b;}};int_n;m1une::ds::SparseTable<RmqMonoid>_st;voidcheck_vertex(intv)const{assert(0<=v&&v<_n);assert(first[v]!=-1);}public:SparseTableLca():root(-1),_n(0){}explicitSparseTableLca(constm1une::graph::Graph<T>&g,introot_=0){build(g,root_);}voidbuild(constm1une::graph::Graph<T>&g,introot_=0){_n=g.size();root=_n==0?-1:root_;parent.assign(_n,-2);parent_edge.assign(_n,-1);depth.assign(_n,0);dist.assign(_n,T(0));subtree_size.assign(_n,0);tin.assign(_n,-1);tout.assign(_n,-1);order.clear();order.reserve(_n);first.assign(_n,-1);euler.clear();euler.reserve(std::max(0,2*_n-1));_st=m1une::ds::SparseTable<RmqMonoid>();if(_n==0)return;assert(0<=root&&root<_n);std::vector<int>it(_n,0);std::vector<char>visited(_n,false);std::vector<int>stack={root};visited[root]=true;parent[root]=-1;inttimer=0;tin[root]=timer++;order.push_back(root);first[root]=0;euler.push_back(root);while(!stack.empty()){intv=stack.back();if(it[v]<int(g[v].size())){constauto&e=g[v][it[v]++];if(!e.alive)continue;if(visited[e.to])continue;visited[e.to]=true;parent[e.to]=v;parent_edge[e.to]=e.id;depth[e.to]=depth[v]+1;dist[e.to]=dist[v]+e.cost;tin[e.to]=timer++;order.push_back(e.to);first[e.to]=int(euler.size());euler.push_back(e.to);stack.push_back(e.to);}else{subtree_size[v]++;if(parent[v]!=-1)subtree_size[parent[v]]+=subtree_size[v];tout[v]=timer;stack.pop_back();if(!stack.empty())euler.push_back(stack.back());}}std::vector<RmqNode>rmq;rmq.reserve(euler.size());for(intv:euler)rmq.push_back({depth[v],v});_st=m1une::ds::SparseTable<RmqMonoid>(std::move(rmq));}intsize()const{return_n;}boolempty()const{return_n==0;}boolis_ancestor(intu,intv)const{check_vertex(u);check_vertex(v);returntin[u]<=tin[v]&&tout[v]<=tout[u];}boolin_subtree(intv,intu)const{returnis_ancestor(u,v);}intlca(intu,intv)const{check_vertex(u);check_vertex(v);intl=first[u],r=first[v];if(l>r)std::swap(l,r);return_st.prod(l,r+1).vertex;}intdist_edges(intu,intv)const{intw=lca(u,v);returndepth[u]+depth[v]-2*depth[w];}Tdist_cost(intu,intv)const{intw=lca(u,v);returndist[u]+dist[v]-dist[w]-dist[w];}std::pair<int,int>subtree_range(intv)const{check_vertex(v);return{tin[v],tout[v]};}};}// namespace tree}// namespace m1une#line 1 "graph/tree/static_top_tree.hpp"
#line 10 "graph/tree/static_top_tree.hpp"
#line 12 "graph/tree/static_top_tree.hpp"
namespacem1une{namespacetree{namespaceinternal{enumclassStaticTopTreeNodeType{Compress,Rake,AddEdge,AddVertex,};}// namespace internaltemplate<classT,classVertex,classPath,classPoint,classCompress,classRake,classAddEdge,classAddVertex>structStaticTopTree{usingcost_type=T;usingvertex_type=Vertex;usingpath_type=Path;usingpoint_type=Point;usingedge_type=m1une::graph::Edge<T>;private:structNode{internal::StaticTopTreeNodeTypetype;intleft=-1;intright=-1;intparent=-1;intvertex=-1;edge_typeedge;intsize=0;intheight=1;std::optional<Path>path;std::optional<Point>point;};int_n;int_root;int_root_node;Point_point_id;Compress_compress;Rake_rake;AddEdge_add_edge;AddVertex_add_vertex;std::vector<Vertex>_values;std::vector<Node>_nodes;std::vector<int>_vertex_node;std::vector<int>_edge_node;std::vector<int>_parent;std::vector<int>_subtree_size;std::vector<int>_heavy;std::vector<edge_type>_heavy_edge;std::vector<std::vector<edge_type>>_children;constPath&path_value(intnode)const{assert(0<=node&&node<int(_nodes.size()));assert(_nodes[node].path.has_value());return*_nodes[node].path;}constPoint&point_value(intnode)const{assert(0<=node&&node<int(_nodes.size()));assert(_nodes[node].point.has_value());return*_nodes[node].point;}voidset_parent(intchild,intparent){if(child!=-1)_nodes[child].parent=parent;}voidrecompute(intnode){auto&x=_nodes[node];if(x.type==internal::StaticTopTreeNodeType::Compress){x.path=_compress(path_value(x.left),path_value(x.right),x.edge);}elseif(x.type==internal::StaticTopTreeNodeType::Rake){x.point=_rake(point_value(x.left),point_value(x.right));}elseif(x.type==internal::StaticTopTreeNodeType::AddEdge){x.point=_add_edge(path_value(x.left),x.edge);}else{constPoint&side=x.left==-1?_point_id:point_value(x.left);x.path=_add_vertex(side,_values[x.vertex],x.vertex);}}intnew_node(Nodenode){intid=int(_nodes.size());_nodes.push_back(std::move(node));set_parent(_nodes[id].left,id);set_parent(_nodes[id].right,id);recompute(id);returnid;}intnew_compress(intleft,intright,edge_typeedge){Nodenode;node.type=internal::StaticTopTreeNodeType::Compress;node.left=left;node.right=right;node.edge=edge;node.size=_nodes[left].size+_nodes[right].size;node.height=std::max(_nodes[left].height,_nodes[right].height)+1;intid=new_node(std::move(node));if(0<=edge.id&&edge.id<int(_edge_node.size()))_edge_node[edge.id]=id;returnid;}intnew_rake(intleft,intright){Nodenode;node.type=internal::StaticTopTreeNodeType::Rake;node.left=left;node.right=right;node.size=_nodes[left].size+_nodes[right].size;node.height=std::max(_nodes[left].height,_nodes[right].height)+1;returnnew_node(std::move(node));}intnew_add_edge(intchild,edge_typeedge){Nodenode;node.type=internal::StaticTopTreeNodeType::AddEdge;node.left=child;node.edge=edge;node.size=_nodes[child].size;node.height=_nodes[child].height+1;intid=new_node(std::move(node));if(0<=edge.id&&edge.id<int(_edge_node.size()))_edge_node[edge.id]=id;returnid;}intnew_add_vertex(intside,intvertex){Nodenode;node.type=internal::StaticTopTreeNodeType::AddVertex;node.left=side;node.vertex=vertex;node.size=1+(side==-1?0:_nodes[side].size);node.height=1+(side==-1?0:_nodes[side].height);intid=new_node(std::move(node));_vertex_node[vertex]=id;returnid;}intweighted_split(conststd::vector<int>&nodes,intl,intr)const{inttotal=0;for(inti=l;i<r;i++)total+=_nodes[nodes[i]].size;intleft_sum=0;for(inti=l;i+1<r;i++){left_sum+=_nodes[nodes[i]].size;if(2*left_sum>=total)returni+1;}returnr-1;}intbuild_rake(conststd::vector<int>&nodes,intl,intr){if(l==r)return-1;if(l+1==r)returnnodes[l];intm=weighted_split(nodes,l,r);returnnew_rake(build_rake(nodes,l,m),build_rake(nodes,m,r));}intbuild_compress(conststd::vector<int>&nodes,conststd::vector<edge_type>&edges,intl,intr){if(l+1==r)returnnodes[l];intm=weighted_split(nodes,l,r);returnnew_compress(build_compress(nodes,edges,l,m),build_compress(nodes,edges,m,r),edges[m-1]);}intbuild_vertex(intv){std::vector<int>side_nodes;for(constauto&e:_children[v]){if(e.to==_heavy[v])continue;intchild_path=build_path(e.to);side_nodes.push_back(new_add_edge(child_path,e));}returnnew_add_vertex(build_rake(side_nodes,0,int(side_nodes.size())),v);}intbuild_path(intstart){std::vector<int>path_nodes;std::vector<edge_type>path_edges;for(intv=start;v!=-1;v=_heavy[v]){path_nodes.push_back(build_vertex(v));if(_heavy[v]!=-1)path_edges.push_back(_heavy_edge[v]);}returnbuild_compress(path_nodes,path_edges,0,int(path_nodes.size()));}voidrecompute_up(intnode){while(node!=-1){recompute(node);node=_nodes[node].parent;}}public:StaticTopTree(constm1une::graph::Graph<T>&g,conststd::vector<Vertex>&values,Pointpoint_id,Compresscompress,Rakerake,AddEdgeadd_edge,AddVertexadd_vertex,introot=0):_n(g.size()),_root(_n==0?-1:root),_root_node(-1),_point_id(std::move(point_id)),_compress(std::move(compress)),_rake(std::move(rake)),_add_edge(std::move(add_edge)),_add_vertex(std::move(add_vertex)),_values(values){build(g,root);}voidbuild(constm1une::graph::Graph<T>&g,introot=0){_n=g.size();_root=_n==0?-1:root;assert(int(_values.size())==_n);_nodes.clear();_vertex_node.assign(_n,-1);_edge_node.assign(g.edge_count(),-1);_parent.assign(_n,-2);_subtree_size.assign(_n,1);_heavy.assign(_n,-1);_heavy_edge.assign(_n,edge_type());_children.assign(_n,{});_root_node=-1;if(_n==0)return;assert(0<=root&&root<_n);assert(int(g.edges().size())==_n-1);std::vector<int>order;order.reserve(_n);std::vector<int>stack={root};_parent[root]=-1;while(!stack.empty()){intv=stack.back();stack.pop_back();order.push_back(v);for(constauto&e:g[v]){if(!e.alive)continue;if(_parent[e.to]!=-2)continue;_parent[e.to]=v;_children[v].push_back(e);stack.push_back(e.to);}}assert(int(order.size())==_n);for(inti=int(order.size())-1;i>=0;i--){intv=order[i];for(constauto&e:_children[v]){_subtree_size[v]+=_subtree_size[e.to];if(_heavy[v]==-1||_subtree_size[_heavy[v]]<_subtree_size[e.to]){_heavy[v]=e.to;_heavy_edge[v]=e;}}}_root_node=build_path(root);}intsize()const{return_n;}boolempty()const{return_n==0;}introot()const{return_root;}intnode_count()const{returnint(_nodes.size());}intheight()const{return_root_node==-1?0:_nodes[_root_node].height;}constVertex&get(intv)const{assert(0<=v&&v<_n);return_values[v];}constVertex&operator[](intv)const{returnget(v);}voidset(intv,constVertex&value){assert(0<=v&&v<_n);assert(_vertex_node[v]!=-1);_values[v]=value;recompute_up(_vertex_node[v]);}voidset(intv,Vertex&&value){assert(0<=v&&v<_n);assert(_vertex_node[v]!=-1);_values[v]=std::move(value);recompute_up(_vertex_node[v]);}voidset_edge_cost(intedge_id,Tcost){assert(0<=edge_id&&edge_id<int(_edge_node.size()));intnode=_edge_node[edge_id];assert(node!=-1);_nodes[node].edge.cost=cost;recompute_up(node);}constPath&all_prod()const{assert(_root_node!=-1);returnpath_value(_root_node);}constPath&query()const{returnall_prod();}};template<classT,classVertex,classPoint,classCompress,classRake,classAddEdge,classAddVertex>StaticTopTree(constm1une::graph::Graph<T>&,conststd::vector<Vertex>&,Point,Compress,Rake,AddEdge,AddVertex,int)->StaticTopTree<T,Vertex,std::invoke_result_t<AddVertex,Point,Vertex,int>,Point,Compress,Rake,AddEdge,AddVertex>;template<classT,classVertex,classPoint,classCompress,classRake,classAddEdge,classAddVertex>StaticTopTree(constm1une::graph::Graph<T>&,conststd::vector<Vertex>&,Point,Compress,Rake,AddEdge,AddVertex)->StaticTopTree<T,Vertex,std::invoke_result_t<AddVertex,Point,Vertex,int>,Point,Compress,Rake,AddEdge,AddVertex>;}// namespace tree}// namespace m1une#line 1 "graph/tree/tree.hpp"
#line 9 "graph/tree/tree.hpp"
#line 1 "graph/tree/tree_hash.hpp"
#line 9 "graph/tree/tree_hash.hpp"
#line 11 "graph/tree/tree_hash.hpp"
namespacem1une{namespacetree{usingTreeHashValue=std::array<std::uint64_t,2>;classTreeHasher{private:staticconstexprstd::uint64_tmod=(std::uint64_t(1)<<61)-1;std::uint64_t_seed;staticstd::uint64_tsplitmix64(std::uint64_tx){x+=0x9e3779b97f4a7c15ULL;x=(x^(x>>30))*0xbf58476d1ce4e5b9ULL;x=(x^(x>>27))*0x94d049bb133111ebULL;returnx^(x>>31);}staticstd::uint64_tmul_mod(std::uint64_ta,std::uint64_tb){__uint128_tproduct=static_cast<__uint128_t>(a)*b;std::uint64_tresult=std::uint64_t(product&mod)+std::uint64_t(product>>61);if(mod<=result)result-=mod;returnresult;}staticstd::uint64_tadd_mod(std::uint64_ta,std::uint64_tb){std::uint64_tresult=a+b;if(mod<=result)result-=mod;returnresult;}TreeHashValuesalt(intheight)const{std::uint64_tx=static_cast<std::uint64_t>(height);std::uint64_tfirst=splitmix64(_seed^(x+0x243f6a8885a308d3ULL));std::uint64_tsecond=splitmix64(_seed^(x+0x13198a2e03707344ULL));return{first%(mod-1)+1,second%(mod-1)+1};}template<classT>staticstd::vector<int>tree_centers(constm1une::graph::Graph<T>&g){intn=g.size();if(n==0)return{};std::vector<int>degree(n,0);std::vector<int>queue;queue.reserve(n);longlongactive_arcs=0;for(intv=0;v<n;v++){for(constauto&e:g[v]){if(!e.alive)continue;degree[v]++;active_arcs++;}if(degree[v]<=1)queue.push_back(v);}assert(active_arcs==2LL*(n-1));std::vector<char>removed(n,false);intremaining=n;inthead=0;while(2<remaining){intlayer_end=int(queue.size());assert(head<layer_end);remaining-=layer_end-head;while(head<layer_end){intv=queue[head++];removed[v]=true;for(constauto&e:g[v]){if(!e.alive||removed[e.to])continue;if(--degree[e.to]==1)queue.push_back(e.to);}}}std::vector<int>centers;for(intv=0;v<n;v++){if(!removed[v])centers.push_back(v);}assert(1<=int(centers.size())&&int(centers.size())<=2);returncenters;}public:explicitTreeHasher(std::uint64_tseed=0x6a09e667f3bcc909ULL):_seed(seed){}std::uint64_tseed()const{return_seed;}template<classT>std::vector<TreeHashValue>hash_subtrees(constm1une::graph::Graph<T>&g,introot=0)const{intn=g.size();if(n==0)return{};assert(0<=root&&root<n);std::vector<int>parent(n,-1);std::vector<int>order;order.reserve(n);parent[root]=root;order.push_back(root);longlongactive_arcs=0;for(intv=0;v<n;v++){for(constauto&e:g[v])active_arcs+=e.alive;}assert(active_arcs==2LL*(n-1));for(inti=0;i<int(order.size());i++){intv=order[i];for(constauto&e:g[v]){if(!e.alive||parent[e.to]!=-1)continue;parent[e.to]=v;order.push_back(e.to);}}assert(int(order.size())==n);std::vector<int>height(n,0);std::vector<TreeHashValue>result(n,TreeHashValue{1,1});for(inti=n-1;i>=0;i--){intv=order[i];for(constauto&e:g[v]){if(!e.alive||parent[e.to]!=v)continue;height[v]=std::max(height[v],height[e.to]+1);}TreeHashValuerandom=salt(height[v]);for(constauto&e:g[v]){if(!e.alive||parent[e.to]!=v)continue;result[v][0]=mul_mod(result[v][0],add_mod(result[e.to][0],random[0]));result[v][1]=mul_mod(result[v][1],add_mod(result[e.to][1],random[1]));}}returnresult;}template<classT>TreeHashValuehash_rooted(constm1une::graph::Graph<T>&g,introot=0)const{if(g.empty())return{0,0};returnhash_subtrees(g,root)[root];}template<classT>std::vector<TreeHashValue>hash_unrooted(constm1une::graph::Graph<T>&g)const{std::vector<int>centers=tree_centers(g);std::vector<TreeHashValue>result;result.reserve(centers.size());for(intcenter:centers)result.push_back(hash_rooted(g,center));std::sort(result.begin(),result.end());returnresult;}};}// namespace tree}// namespace m1une#line 1 "graph/tree/virtual_tree.hpp"
#line 8 "graph/tree/virtual_tree.hpp"
#line 11 "graph/tree/virtual_tree.hpp"
namespacem1une{namespacetree{template<classT=int>structVirtualTreeResult{std::vector<int>vertex;std::vector<int>parent;std::vector<int>parent_edge_count;std::vector<T>parent_cost;std::vector<std::vector<int>>children;std::vector<bool>is_key;intsize()const{returnint(vertex.size());}boolempty()const{returnvertex.empty();}intedge_count()const{returnvertex.empty()?0:int(vertex.size())-1;}introot()const{returnvertex.empty()?-1:0;}introot_vertex()const{returnvertex.empty()?-1:vertex[0];}};template<classT=int>structVirtualTree{usingcost_type=T;usingresult_type=VirtualTreeResult<T>;private:SparseTableLca<T>_lca;std::vector<int>_key;std::vector<int>_vertices;std::vector<int>_stack;public:VirtualTree()=default;explicitVirtualTree(constm1une::graph::Graph<T>&graph,introot=0):_lca(graph,root){}voidbuild_lca(constm1une::graph::Graph<T>&graph,introot=0){_lca.build(graph,root);}intoriginal_size()const{return_lca.size();}constSparseTableLca<T>&lca_data()const{return_lca;}result_typebuild(std::vector<int>key_vertices){result_typeresult;if(key_vertices.empty())returnresult;autoby_tin=[&](intu,intv){return_lca.tin[u]<_lca.tin[v];};for(intv:key_vertices){assert(0<=v&&v<_lca.size());assert(_lca.tin[v]!=-1);}std::sort(key_vertices.begin(),key_vertices.end(),by_tin);key_vertices.erase(std::unique(key_vertices.begin(),key_vertices.end()),key_vertices.end());_key=key_vertices;_vertices=key_vertices;_vertices.reserve(2*_key.size());for(inti=1;i<int(_key.size());i++){_vertices.push_back(_lca.lca(_key[i-1],_key[i]));}std::sort(_vertices.begin(),_vertices.end(),by_tin);_vertices.erase(std::unique(_vertices.begin(),_vertices.end()),_vertices.end());intn=int(_vertices.size());result.vertex=_vertices;result.parent.assign(n,-1);result.parent_edge_count.assign(n,0);result.parent_cost.assign(n,T(0));result.children.assign(n,{});result.is_key.assign(n,false);intkey_index=0;for(inti=0;i<n;i++){while(key_index<int(_key.size())&&_lca.tin[_key[key_index]]<_lca.tin[_vertices[i]]){key_index++;}if(key_index<int(_key.size())&&_key[key_index]==_vertices[i])result.is_key[i]=true;}_stack.clear();_stack.reserve(n);for(inti=0;i<n;i++){while(!_stack.empty()&&!_lca.is_ancestor(_vertices[_stack.back()],_vertices[i])){_stack.pop_back();}if(!_stack.empty()){intp=_stack.back();result.parent[i]=p;result.parent_edge_count[i]=_lca.depth[_vertices[i]]-_lca.depth[_vertices[p]];result.parent_cost[i]=_lca.dist[_vertices[i]]-_lca.dist[_vertices[p]];result.children[p].push_back(i);}_stack.push_back(i);}returnresult;}};}// namespace tree}// namespace m1une#line 1 "graph/tree/zero_one_on_tree.hpp"
#line 7 "graph/tree/zero_one_on_tree.hpp"
#line 9 "graph/tree/zero_one_on_tree.hpp"
namespacem1une{namespacetree{inlinelonglongzero_one_on_tree(conststd::vector<int>&parent,conststd::vector<int>&value){constintn=int(parent.size());assert(int(value.size())==n);if(n==0)return0;introot=-1;std::vector<std::vector<int>>children(n);for(intv=0;v<n;v++){assert(value[v]==0||value[v]==1);if(parent[v]==-1){assert(root==-1);root=v;}else{assert(0<=parent[v]&&parent[v]<n&&parent[v]!=v);children[parent[v]].push_back(v);}}assert(root!=-1);std::vector<int>stack(1,root);std::vector<char>visited(n,false);visited[root]=true;intvisited_count=0;while(!stack.empty()){constintv=stack.back();stack.pop_back();visited_count++;for(intchild:children[v]){assert(!visited[child]);visited[child]=true;stack.push_back(child);}}assert(visited_count==n);structComponent{longlongzeros;longlongones;intvertex;};structCompare{booloperator()(constComponent&lhs,constComponent&rhs)const{constlonglonglhs_product=lhs.zeros*rhs.ones;constlonglongrhs_product=rhs.zeros*lhs.ones;if(lhs_product!=rhs_product)returnlhs_product<rhs_product;returnlhs.vertex<rhs.vertex;}};std::vector<longlong>zeros(n),ones(n);std::vector<int>dsu(n);std::set<Component,Compare>components;for(intv=0;v<n;v++){zeros[v]=value[v]==0;ones[v]=value[v]==1;dsu[v]=v;if(v!=root)components.insert(Component{zeros[v],ones[v],v});}autoleader=[&](intv){intresult=v;while(dsu[result]!=result)result=dsu[result];while(dsu[v]!=v){constintnext=dsu[v];dsu[v]=result;v=next;}returnresult;};longlonganswer=0;while(!components.empty()){autoit=components.end();--it;constComponentchild=*it;components.erase(it);constintp=leader(parent[child.vertex]);if(p!=root){constinterased=int(components.erase(Component{zeros[p],ones[p],p}));assert(erased==1);}answer+=ones[p]*zeros[child.vertex];zeros[p]+=zeros[child.vertex];ones[p]+=ones[child.vertex];dsu[child.vertex]=p;if(p!=root)components.insert(Component{zeros[p],ones[p],p});}returnanswer;}template<classT>longlongzero_one_on_tree(constm1une::graph::Graph<T>&graph,conststd::vector<int>&value,introot=0){constintn=graph.size();assert(int(value.size())==n);if(n==0)return0;assert(0<=root&&root<n);assert(int(graph.edges().size())==n-1);RootedTree<T>rooted_tree(graph,root);assert(int(rooted_tree.order.size())==n);returnzero_one_on_tree(rooted_tree.parent,value);}}// namespace tree}// namespace m1une#line 23 "graph/tree/all.hpp"
#line 14 "verify/graph/tree/tree_algorithms.test.cpp"
usingm1une::graph::Graph;template<classHld>std::vector<int>expand_segments(constHld&hld,conststd::vector<m1une::tree::HldPathSegment>&segments){std::vector<int>result;for(autoseg:segments){if(seg.reversed){for(inti=seg.r-1;i>=seg.l;i--)result.push_back(hld.order[i]);}else{for(inti=seg.l;i<seg.r;i++)result.push_back(hld.order[i]);}}returnresult;}Graph<longlong>sample_tree(){Graph<longlong>g(7);g.add_edge(0,1,3);g.add_edge(0,2,2);g.add_edge(1,3,4);g.add_edge(1,4,1);g.add_edge(2,5,6);g.add_edge(5,6,2);returng;}voidtest_rooted_tree(){autog=sample_tree();m1une::tree::RootedTree<longlong>tree(g,0);assert(tree.size()==7);assert(!tree.empty());assert(tree.root==0);assert(tree.parent[0]==-1);assert(tree.parent[3]==1);assert(tree.depth[6]==3);assert(tree.dist[6]==10);assert(tree.subtree_size[0]==7);assert(tree.subtree_size[1]==3);assert(tree.is_ancestor(1,4));assert(!tree.is_ancestor(2,4));assert(tree.in_subtree(4,1));assert(tree.kth_ancestor(6,0)==6);assert(tree.kth_ancestor(6,1)==5);assert(tree.kth_ancestor(6,3)==0);assert(tree.kth_ancestor(6,4)==-1);assert(tree.lca(3,4)==1);assert(tree.lca(3,6)==0);assert(tree.dist_edges(3,6)==5);assert(tree.dist_cost(3,6)==17);assert(tree.jump(3,6,0)==3);assert(tree.jump(3,6,1)==1);assert(tree.jump(3,6,2)==0);assert(tree.jump(3,6,3)==2);assert(tree.jump(3,6,5)==6);assert(tree.jump(3,6,6)==-1);std::vector<int>expected_path={3,1,0,2,5,6};assert(tree.path(3,6)==expected_path);std::vector<int>expected_edges={2,0,1,4,5};assert(tree.path_edges(3,6)==expected_edges);auto[l,r]=tree.subtree_range(1);assert(r-l==3);autosub=tree.subtree_vertices(1);std::sort(sub.begin(),sub.end());assert((sub==std::vector<int>{1,3,4}));}voidtest_euler_tour(){autog=sample_tree();m1une::tree::EulerTour<longlong>tour(g,0);std::vector<int>expected_order={0,1,3,4,2,5,6};assert(tour.size()==7);assert(tour.visited_size()==7);assert(tour.root==0);assert(tour.order==expected_order);assert(tour.parent[6]==5);assert(tour.parent_edge[6]==5);assert(tour.depth[6]==3);assert(tour.dist[6]==10);assert(tour.subtree_size[1]==3);assert(tour.is_ancestor(1,4));assert(!tour.is_ancestor(2,4));auto[l,r]=tour.subtree_range(1);assert(l==1);assert(r==4);auto[el,er]=tour.subtree_range(1,true);assert(el==2);assert(er==4);std::vector<int>subtree=tour.subtree_vertices(1);std::sort(subtree.begin(),subtree.end());std::vector<int>expected_subtree={1,3,4};assert(subtree==expected_subtree);}voidtest_sparse_table_lca(){autog=sample_tree();m1une::tree::RootedTree<longlong>tree(g,0);m1une::tree::SparseTableLca<longlong>lca(g,0);assert(lca.size()==7);assert(!lca.empty());assert(lca.root==0);assert(lca.parent[0]==-1);assert(lca.parent[6]==5);assert(lca.depth[6]==3);assert(lca.dist[6]==10);assert(lca.euler.size()==13);assert(lca.first[0]==0);assert(lca.is_ancestor(2,6));assert(!lca.is_ancestor(1,6));assert(lca.in_subtree(6,2));for(intu=0;u<7;u++){for(intv=0;v<7;v++){assert(lca.lca(u,v)==tree.lca(u,v));assert(lca.dist_edges(u,v)==tree.dist_edges(u,v));assert(lca.dist_cost(u,v)==tree.dist_cost(u,v));}}auto[l,r]=lca.subtree_range(2);assert(r-l==3);std::vector<int>subtree;for(inti=l;i<r;i++)subtree.push_back(lca.order[i]);std::sort(subtree.begin(),subtree.end());assert((subtree==std::vector<int>{2,5,6}));}voidtest_virtual_tree(){autograph=sample_tree();m1une::tree::VirtualTree<longlong>builder(graph,0);autovirtual_tree=builder.build(std::vector<int>{3,4,6,3});std::vector<int>expected_vertices={0,1,3,4,6};assert(virtual_tree.vertex==expected_vertices);assert(virtual_tree.parent==std::vector<int>({-1,0,1,1,0}));assert(virtual_tree.parent_edge_count==std::vector<int>({0,1,1,1,3}));assert(virtual_tree.parent_cost==std::vector<longlong>({0,3,4,1,10}));assert(virtual_tree.is_key==std::vector<bool>({false,false,true,true,true}));assert(virtual_tree.children[0]==std::vector<int>({1,4}));assert(virtual_tree.children[1]==std::vector<int>({2,3}));assert(virtual_tree.root()==0);assert(virtual_tree.root_vertex()==0);assert(virtual_tree.edge_count()==4);autosingleton=builder.build(std::vector<int>{5,5});assert(singleton.size()==1);assert(singleton.vertex[0]==5);assert(singleton.parent[0]==-1);assert(singleton.is_key[0]);autoempty=builder.build({});assert(empty.empty());assert(empty.root()==-1);assert(empty.root_vertex()==-1);assert(empty.edge_count()==0);std::mt19937random(123456789);for(inttest=0;test<100;test++){intn=1+random()%200;Graph<longlong>random_graph(n);for(intv=1;v<n;v++){intparent=random()%v;longlongcost=1+random()%1000000;random_graph.add_edge(parent,v,cost);}m1une::tree::VirtualTree<longlong>random_builder(random_graph,0);constauto&lca=random_builder.lca_data();for(intquery=0;query<100;query++){intk=random()%(2*n+1);std::vector<int>keys(k);for(int&v:keys)v=random()%n;autoresult=random_builder.build(keys);std::sort(keys.begin(),keys.end(),[&](intu,intv){returnlca.tin[u]<lca.tin[v];});keys.erase(std::unique(keys.begin(),keys.end()),keys.end());std::vector<int>expected=keys;for(inti=1;i<int(keys.size());i++)expected.push_back(lca.lca(keys[i-1],keys[i]));std::sort(expected.begin(),expected.end(),[&](intu,intv){returnlca.tin[u]<lca.tin[v];});expected.erase(std::unique(expected.begin(),expected.end()),expected.end());assert(result.vertex==expected);intkey_index=0;for(inti=0;i<result.size();i++){while(key_index<int(keys.size())&&lca.tin[keys[key_index]]<lca.tin[result.vertex[i]]){key_index++;}boolis_key=key_index<int(keys.size())&&keys[key_index]==result.vertex[i];assert(result.is_key[i]==is_key);if(i==0){assert(result.parent[i]==-1);continue;}intparent=result.parent[i];assert(0<=parent&&parent<i);assert(lca.is_ancestor(result.vertex[parent],result.vertex[i]));assert(result.parent_edge_count[i]==lca.dist_edges(result.vertex[parent],result.vertex[i]));assert(result.parent_cost[i]==lca.dist_cost(result.vertex[parent],result.vertex[i]));for(intj=parent+1;j<i;j++){assert(!lca.is_ancestor(result.vertex[j],result.vertex[i]));}}}}}voidtest_hld(){autog=sample_tree();m1une::tree::HeavyLightDecomposition<longlong>hld(g,0);assert(hld.size()==7);assert(hld.root==0);assert(hld.lca(3,4)==1);assert(hld.lca(3,6)==0);assert(hld.dist_edges(3,6)==5);assert(hld.dist_cost(3,6)==17);assert(hld.kth_ancestor(6,2)==2);assert(hld.kth_ancestor(6,4)==-1);assert(hld.jump(3,6,4)==5);std::vector<int>expected_path={3,1,0,2,5,6};assert(expand_segments(hld,hld.path_segments(3,6))==expected_path);std::vector<int>expected_edge_vertices={3,1,2,5,6};assert(expand_segments(hld,hld.path_segments(3,6,true))==expected_edge_vertices);intsegment_count=0;hld.for_each_path(3,6,[&](intl,intr,bool){assert(l<r);segment_count++;});assert(segment_count==int(hld.path_segments(3,6).size()));auto[vl,vr]=hld.subtree_range(1);std::vector<int>subtree;for(inti=vl;i<vr;i++)subtree.push_back(hld.order[i]);std::sort(subtree.begin(),subtree.end());assert((subtree==std::vector<int>{1,3,4}));auto[el,er]=hld.subtree_range(1,true);std::vector<int>edge_subtree;for(inti=el;i<er;i++)edge_subtree.push_back(hld.order[i]);std::sort(edge_subtree.begin(),edge_subtree.end());assert((edge_subtree==std::vector<int>{3,4}));}voidtest_diameter(){autog=sample_tree();autodiameter=m1une::tree::tree_diameter(g);assert(!diameter.empty());assert(diameter.cost==17);assert(diameter.edge_count==5);assert(diameter.from==diameter.vertices.front());assert(diameter.to==diameter.vertices.back());std::set<int>endpoints={diameter.from,diameter.to};assert((endpoints==std::set<int>{3,6}));g.erase_edge(1);autosplit=m1une::tree::tree_diameter(g);assert(split.cost==8);assert(split.edge_count==2);}voidtest_rerooting(){autog=sample_tree();autocomponent_size=m1une::tree::rerooting_dp(g,0,[](inta,intb){returna+b;},[](intacc,int){returnacc+1;},[](intdp,constauto&){returndp;});assert(component_size==std::vector<int>(7,7));autoeccentricity_edges=m1une::tree::rerooting_dp(g,0,[](inta,intb){returnstd::max(a,b);},[](intacc,int){returnacc;},[](intdp,constauto&){returndp+1;});assert(eccentricity_edges[0]==3);assert(eccentricity_edges[3]==5);assert(eccentricity_edges[6]==5);autoeccentricity_cost=m1une::tree::rerooting_dp(g,0LL,[](longlonga,longlongb){returnstd::max(a,b);},[](longlongacc,int){returnacc;},[](longlongdp,constauto&e){returndp+e.cost;});assert(eccentricity_cost[0]==10);assert(eccentricity_cost[3]==17);assert(eccentricity_cost[6]==17);}structDistancePath{longlongcount;longlongsum;longlonglength;};structDistancePoint{longlongcount;longlongsum;};structColorVertex{longlongweight;intcolor;};structColorPath{intfirst_color;intlast_color;longlongfirst_sum;longlonglast_sum;boolconnected;};structColorPoint{std::array<longlong,2>sum;};voidtest_static_top_tree(){autog=sample_tree();std::vector<longlong>values={1,2,3,4,5,6,7};autovertex_sum=m1une::tree::StaticTopTree(g,values,0LL,[](longlongtop,longlongbottom,constauto&){returntop+bottom;},[](longlonga,longlongb){returna+b;},[](longlongpath,constauto&){returnpath;},[](longlongside,longlongvalue,int){returnside+value;});assert(vertex_sum.size()==7);assert(vertex_sum.root()==0);assert(vertex_sum.all_prod()==28);assert(vertex_sum.query()==28);assert(vertex_sum.get(3)==4);assert(vertex_sum.height()>0);vertex_sum.set(3,100);assert(vertex_sum[3]==100);assert(vertex_sum.all_prod()==124);autoroot_distance_sum=m1une::tree::StaticTopTree(g,std::vector<int>(7,0),DistancePoint{0,0},[](DistancePathtop,DistancePathbottom,constauto&e){longlongshift=top.length+e.cost;returnDistancePath{top.count+bottom.count,top.sum+bottom.sum+bottom.count*shift,top.length+e.cost+bottom.length};},[](DistancePointa,DistancePointb){returnDistancePoint{a.count+b.count,a.sum+b.sum};},[](DistancePathpath,constauto&e){returnDistancePoint{path.count,path.sum+path.count*e.cost};},[](DistancePointside,int,int){returnDistancePath{side.count+1,side.sum,0};});assert(root_distance_sum.all_prod().count==7);assert(root_distance_sum.all_prod().sum==34);root_distance_sum.set_edge_cost(0,10);assert(root_distance_sum.all_prod().sum==55);root_distance_sum.set_edge_cost(1,10);assert(root_distance_sum.all_prod().sum==79);}voidtest_rerooting_static_top_tree(){Graph<longlong>g(3);inte01=g.add_edge(0,1,2);inte12=g.add_edge(1,2,5);std::vector<longlong>weights={1,1,1};autostt=m1une::tree::RerootingStaticTopTree(g,weights,DistancePoint{0,0},[](DistancePathupper,DistancePathlower,constauto&e){longlongshift=upper.length+e.cost;returnDistancePath{upper.count+lower.count,upper.sum+lower.sum+lower.count*shift,upper.length+e.cost+lower.length};},[](DistancePathlower,DistancePathupper,constauto&e){longlongshift=lower.length+e.cost;returnDistancePath{lower.count+upper.count,lower.sum+upper.sum+upper.count*shift,lower.length+e.cost+upper.length};},[](DistancePointa,DistancePointb){returnDistancePoint{a.count+b.count,a.sum+b.sum};},[](DistancePathpath,constauto&e){returnDistancePoint{path.count,path.sum+path.count*e.cost};},[](DistancePathpath,constauto&e){returnDistancePoint{path.count,path.sum+path.count*e.cost};},[](DistancePointside,longlongweight,int){returnDistancePath{side.count+weight,side.sum,0};});assert(stt.size()==3);assert(stt.root()==0);assert(stt.node_count()>=3);assert(stt.height()>0);assert(stt.all_prod_down().count==3);assert(stt.all_prod_down().sum==9);assert(stt.all_prod_down().length==7);assert(stt.all_prod_up().count==3);assert(stt.all_prod_up().sum==12);assert(stt.all_prod_up().length==7);introot_node=stt.root_node();assert(stt.path_down(root_node).sum==stt.all_prod_down().sum);assert(stt.path_up(root_node).sum==stt.all_prod_up().sum);intone_node=stt.vertex_node(1);assert(stt.node(one_node).type==m1une::tree::internal::RerootingStaticTopTreeNodeType::AddVertex);assert(stt.parent_node(root_node)==-1);assert(stt.point_id().count==0);assert(stt.local_point_node(1)==-1);assert(stt.local_point(1).count==0);usingRerootingStepType=decltype(stt)::step_type;usingRerootingNodeType=decltype(stt)::node_type;autosteps=stt.rerooting_steps(1);std::vector<decltype(stt)::RerootingStep>streamed_steps;stt.for_each_rerooting_step(1,[&](constauto&step){streamed_steps.push_back(step);});assert(streamed_steps.size()==steps.size());intcur=one_node;for(inti=0;i<int(steps.size());i++){constauto&step=steps[i];constauto&streamed=streamed_steps[i];assert(streamed.type==step.type);assert(streamed.node==step.node);assert(streamed.sibling==step.sibling);assert(streamed.vertex==step.vertex);assert(streamed.edge.from==step.edge.from);assert(streamed.edge.to==step.edge.to);assert(streamed.edge.id==step.edge.id);assert(stt.parent_node(cur)==step.node);constauto&parent=stt.node(step.node);if(step.type==RerootingStepType::CompressLower){assert(parent.type==RerootingNodeType::Compress);assert(parent.left==cur);assert(parent.right==step.sibling);assert(stt.node(step.sibling).path_down.has_value());}elseif(step.type==RerootingStepType::CompressUpper){assert(parent.type==RerootingNodeType::Compress);assert(parent.right==cur);assert(parent.left==step.sibling);assert(stt.node(step.sibling).path_up.has_value());}elseif(step.type==RerootingStepType::RakeLeft){assert(parent.type==RerootingNodeType::Rake);assert(parent.right==cur);assert(parent.left==step.sibling);assert(stt.node(step.sibling).point.has_value());}elseif(step.type==RerootingStepType::RakeRight){assert(parent.type==RerootingNodeType::Rake);assert(parent.left==cur);assert(parent.right==step.sibling);assert(stt.node(step.sibling).point.has_value());}elseif(step.type==RerootingStepType::AddEdge){assert(parent.type==RerootingNodeType::AddEdge);assert(parent.left==cur);}else{assert(step.type==RerootingStepType::AddVertex);assert(parent.type==RerootingNodeType::AddVertex);assert(parent.left==cur);assert(parent.vertex==step.vertex);}cur=step.node;}assert(cur==stt.root_node());autoedge=m1une::graph::Edge<longlong>(0,1,2,e01);autoreversed=decltype(stt)::reverse_edge(edge);assert(reversed.from==1);assert(reversed.to==0);DistancePathone=stt.add_vertex(stt.point_id(),1LL,0);assert(one.count==1);assert(one.sum==0);autodown_point=stt.add_edge_down(one,edge);autoup_point=stt.add_edge_up(one,reversed);assert(down_point.sum==2);assert(up_point.sum==2);autoraked=stt.rake(down_point,up_point);assert(raked.count==2);assert(raked.sum==4);assert(stt.compress_down(one,one,edge).sum==2);assert(stt.compress_up(one,one,reversed).sum==2);stt.set_edge_cost(e01,10);assert(stt.all_prod_down().count==3);assert(stt.all_prod_down().sum==25);assert(stt.all_prod_down().length==15);assert(stt.all_prod_up().sum==20);assert(stt.all_prod_up().length==15);stt.set(0,3);assert(stt[0]==3);assert(stt.all_prod_down().count==5);assert(stt.all_prod_down().sum==25);assert(stt.all_prod_up().count==5);assert(stt.all_prod_up().sum==50);stt.set_edge_cost(e12,1);assert(stt.all_prod_down().sum==21);assert(stt.all_prod_up().sum==34);}voidtest_rerooting_static_top_tree_vertex_component(){autog=sample_tree();std::vector<ColorVertex>values={ColorVertex{1,0},ColorVertex{10,0},ColorVertex{100,1},ColorVertex{1000,0},ColorVertex{10000,1},ColorVertex{100000,1},ColorVertex{1000000,1},};autocompress=[](ColorPatha,ColorPathb,constauto&){booljoin=a.last_color==b.first_color;ColorPathres{a.first_color,b.last_color,a.first_sum,b.last_sum,false};if(join&&a.connected)res.first_sum+=b.first_sum;if(join&&b.connected)res.last_sum+=a.last_sum;res.connected=a.connected&&b.connected&&join;returnres;};autorake=[](ColorPointa,ColorPointb){returnColorPoint{a.sum[0]+b.sum[0],a.sum[1]+b.sum[1]};};autoadd_edge=[](ColorPathpath,constauto&){ColorPointres{};res.sum[path.first_color]=path.first_sum;returnres;};autoadd_vertex=[](ColorPointside,ColorVertexvalue,int){longlongsum=value.weight+side.sum[value.color];returnColorPath{value.color,value.color,sum,sum,true};};autostt=m1une::tree::RerootingStaticTopTree(g,values,ColorPoint{0,0},compress,compress,rake,add_edge,add_edge,add_vertex);usingColorStt=decltype(stt);structQueryFolder{constColorStt&stt;conststd::vector<ColorVertex>&values;intcolor=0;longlonganswer=0;booltouches_top=false;booltouches_bottom=false;boolpending_open=false;ColorPointpending{};voidstart(intv,constColorVertex&value,constColorPoint&local){color=value.color;answer=value.weight+local.sum[color];touches_top=true;touches_bottom=true;pending_open=false;pending=stt.point_id();assert(values[v].color==color);}voidcompress_lower(constColorPath&lower,ColorStt::edge_type){boolconnect=touches_bottom&&lower.first_color==color;if(connect)answer+=lower.first_sum;touches_bottom=connect&&lower.connected;}voidcompress_upper(constColorPath&upper,ColorStt::edge_type){boolconnect=touches_top&&upper.first_color==color;if(connect)answer+=upper.first_sum;touches_top=connect&&upper.connected;}voidadd_edge(ColorStt::edge_type){pending_open=touches_top;pending=stt.point_id();}voidrake_left(constColorPoint&point){if(pending_open)pending=stt.rake(point,pending);}voidrake_right(constColorPoint&point){if(pending_open)pending=stt.rake(pending,point);}voidadd_vertex(int,constColorVertex&value){if(pending_open&&value.color==color){answer+=value.weight+pending.sum[color];touches_top=true;touches_bottom=true;}else{touches_top=false;touches_bottom=false;}pending_open=false;pending=stt.point_id();}longlongresult()const{returnanswer;}};autoquery=[&](intv){returnstt.fold_rerooting(v,QueryFolder{stt,values});};autobrute=[&](intstart){intcolor=values[start].color;longlonganswer=0;std::vector<char>seen(g.size(),false);std::vector<int>stack={start};seen[start]=true;while(!stack.empty()){intv=stack.back();stack.pop_back();answer+=values[v].weight;for(constauto&e:g[v]){if(seen[e.to]||values[e.to].color!=color)continue;seen[e.to]=true;stack.push_back(e.to);}}returnanswer;};autocheck_all=[&](){for(intv=0;v<g.size();v++)assert(query(v)==brute(v));};check_all();values[2].color^=1;stt.set(2,values[2]);check_all();values[5].weight+=7;stt.set(5,values[5]);check_all();values[1].color^=1;stt.set(1,values[1]);check_all();values[4].weight+=11;stt.set(4,values[4]);check_all();}voidtest_centroid_decomposition(){autog=sample_tree();m1une::tree::CentroidDecomposition<longlong>cd(g);assert(cd.size()==7);assert(!cd.empty());assert(cd.root()==0);assert(cd.roots==std::vector<int>{0});assert(cd.parent[cd.root()]==-1);assert(cd.depth[cd.root()]==0);assert(cd.order.size()==7);intchild_count=0;for(constauto&ch:cd.children)child_count+=int(ch.size());assert(child_count==6);for(intv=0;v<7;v++){if(v==cd.root())continue;assert(cd.parent[v]!=-1);assert(cd.depth[v]==cd.depth[cd.parent[v]]+1);}}voidtest_forest(){Graph<int>g(4);g.add_edge(0,1,5);g.add_edge(2,3,7);autodiameter=m1une::tree::tree_diameter(g);assert(diameter.cost==7);assert(diameter.edge_count==1);autocomponent_size=m1une::tree::rerooting_dp(g,0,[](inta,intb){returna+b;},[](intacc,int){returnacc+1;},[](intdp,constauto&){returndp;});assert(component_size==std::vector<int>(4,2));m1une::tree::CentroidDecomposition<int>cd(g);assert(cd.roots.size()==2);assert(cd.order.size()==4);}intmain(){m1une::utilities::FastInputfast_input;m1une::utilities::FastOutputfast_output;test_rooted_tree();test_euler_tour();test_sparse_table_lca();test_virtual_tree();test_hld();test_diameter();test_rerooting();test_static_top_tree();test_rerooting_static_top_tree();test_rerooting_static_top_tree_vertex_component();test_centroid_decomposition();test_forest();longlonga=0,b=0;fast_input>>a>>b;fast_output<<a+b<<'\n';}