#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"
#include<cassert>
#include"../../../utilities/fast_io.hpp"
#include<queue>
#include<random>
#include<utility>
#include<vector>#include"../../../ds/dynamic_connectivity/all.hpp"structNaiveDynamicGraph{structEdge{intu;intv;boolalive;};intn;std::vector<Edge>edges;explicitNaiveDynamicGraph(intn):n(n){}intadd_edge(intu,intv){intid=int(edges.size());edges.push_back(Edge{u,v,true});returnid;}boolerase_edge(intid){if(!edges[id].alive)returnfalse;edges[id].alive=false;returntrue;}std::vector<int>component(intstart)const{std::vector<std::vector<int>>graph(n);for(constEdge&edge:edges){if(!edge.alive||edge.u==edge.v)continue;graph[edge.u].push_back(edge.v);graph[edge.v].push_back(edge.u);}std::vector<int>visited(n,false);std::queue<int>queue;std::vector<int>vertices;visited[start]=true;queue.push(start);while(!queue.empty()){intv=queue.front();queue.pop();vertices.push_back(v);for(intto:graph[v]){if(visited[to])continue;visited[to]=true;queue.push(to);}}returnvertices;}boolconnected(intu,intv)const{std::vector<int>vertices=component(u);for(intx:vertices){if(x==v)returntrue;}returnfalse;}intcomponent_count()const{std::vector<bool>visited(n,false);intresult=0;for(intv=0;v<n;v++){if(visited[v])continue;result++;for(intx:component(v))visited[x]=true;}returnresult;}};voidtest_online_basic(){m1une::ds::OnlineDynamicConnectivitygraph(4);graph.reserve_edges(8);inte01=graph.add_edge(0,1);inte12=graph.add_edge(1,2);inte02=graph.add_edge(0,2);intloop=graph.add_edge(3,3);assert(graph.connected(0,2));assert(graph.component_size(0)==3);assert(graph.component_count()==2);assert(graph.active_edge_count()==4);assert(graph.erase_edge(e12));assert(graph.connected(0,2));assert(graph.erase_edge(e02));assert(!graph.connected(0,2));assert(graph.component_count()==3);assert(!graph.erase_edge(e02));assert(graph.erase_edge(loop));assert(graph.erase_edge(e01));assert(graph.component_count()==4);}voidtest_offline_basic(){m1une::ds::OfflineDynamicConnectivitygraph(3);graph.reserve_edges(8);graph.reserve_queries(8);inte01=graph.add_edge(0,1);intq0=graph.add_query(0,2);inte12=graph.add_edge(1,2);intq1=graph.add_query(0,2);assert(graph.erase_edge(e01));intq2=graph.add_query(0,2);assert(!graph.erase_edge(e01));intparallel=graph.add_edge(1,2);intq3=graph.add_query(1,2);assert(graph.erase_edge(e12));intq4=graph.add_query(1,2);assert(graph.erase_edge(parallel));intq5=graph.add_query(1,2);std::vector<bool>answer=graph.solve();assert(!answer[q0]);assert(answer[q1]);assert(!answer[q2]);assert(answer[q3]);assert(answer[q4]);assert(!answer[q5]);assert(answer==graph.solve());intrestored=graph.add_edge(0,2);intq6=graph.add_query(0,2);answer=graph.solve();assert(answer[q6]);assert(graph.erase_edge(restored));}voidtest_online_random(){std::mt19937random(123456789);for(inttest=0;test<80;test++){intn=1+random()%15;m1une::ds::OnlineDynamicConnectivitygraph(n);NaiveDynamicGraphnaive(n);std::vector<int>active;for(intoperation=0;operation<1000;operation++){inttype=random()%5;if(type<=1||active.empty()){intu=random()%n;intv=random()%n;intid=graph.add_edge(u,v);assert(id==naive.add_edge(u,v));active.push_back(id);}elseif(type==2){intindex=random()%active.size();intid=active[index];std::swap(active[index],active.back());active.pop_back();assert(graph.erase_edge(id));assert(naive.erase_edge(id));}else{intu=random()%n;intv=random()%n;assert(graph.connected(u,v)==naive.connected(u,v));assert(graph.component_size(u)==int(naive.component(u).size()));}assert(graph.active_edge_count()==int(active.size()));assert(graph.component_count()==naive.component_count());}}}voidtest_offline_random(){std::mt19937random(987654321);for(inttest=0;test<100;test++){intn=1+random()%12;m1une::ds::OfflineDynamicConnectivitygraph(n);NaiveDynamicGraphnaive(n);std::vector<int>active;std::vector<bool>expected;for(intoperation=0;operation<500;operation++){inttype=random()%4;if(type==0||active.empty()){intu=random()%n;intv=random()%n;intid=graph.add_edge(u,v);assert(id==naive.add_edge(u,v));active.push_back(id);}elseif(type==1){intindex=random()%active.size();intid=active[index];std::swap(active[index],active.back());active.pop_back();assert(graph.erase_edge(id));assert(naive.erase_edge(id));}else{intu=random()%n;intv=random()%n;assert(graph.add_query(u,v)==int(expected.size()));expected.push_back(naive.connected(u,v));}}assert(graph.solve()==expected);}}intmain(){m1une::utilities::FastInputfast_input;m1une::utilities::FastOutputfast_output;test_online_basic();test_offline_basic();test_online_random();test_offline_random();longlonga,b;fast_input>>a>>b;fast_output<<a+b<<'\n';}
#line 1 "verify/ds/dynamic_connectivity/dynamic_connectivity.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/aplusb"
#include<cassert>
#line 1 "utilities/fast_io.hpp"
#include<algorithm>
#include<array>
#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 5 "verify/ds/dynamic_connectivity/dynamic_connectivity.test.cpp"
#include<queue>
#include<random>
#line 9 "verify/ds/dynamic_connectivity/dynamic_connectivity.test.cpp"
#line 1 "ds/dynamic_connectivity/all.hpp"
#line 1 "ds/dynamic_connectivity/offline_dynamic_connectivity.hpp"
#line 8 "ds/dynamic_connectivity/offline_dynamic_connectivity.hpp"
#line 1 "ds/dsu/rollback_dsu.hpp"
#line 7 "ds/dsu/rollback_dsu.hpp"
namespacem1une{namespaceds{structRollbackDsu{private:structHistoryEntry{intfirst;intfirst_value;intsecond;intsecond_value;};int_n;int_component_count;std::vector<int>parent_or_size;std::vector<HistoryEntry>history;staticintcheck_size(intn){assert(0<=n);returnn;}public:RollbackDsu():RollbackDsu(0){}explicitRollbackDsu(intn):_n(check_size(n)),_component_count(_n),parent_or_size(_n,-1){}intsize()const{return_n;}boolempty()const{return_n==0;}intcomponent_count()const{return_component_count;}inthistory_size()const{returnint(history.size());}voidreserve_history(intcount){assert(0<=count);history.reserve(count);}intleader(intvertex)const{assert(0<=vertex&&vertex<_n);while(parent_or_size[vertex]>=0)vertex=parent_or_size[vertex];returnvertex;}boolsame(intfirst,intsecond)const{returnleader(first)==leader(second);}intgroup_size(intvertex)const{return-parent_or_size[leader(vertex)];}intsize(intvertex)const{returngroup_size(vertex);}boolmerge(intfirst,intsecond){first=leader(first);second=leader(second);if(first==second){history.push_back(HistoryEntry{-1,0,-1,0});returnfalse;}if(-parent_or_size[first]<-parent_or_size[second]){std::swap(first,second);}history.push_back(HistoryEntry{first,parent_or_size[first],second,parent_or_size[second]});parent_or_size[first]+=parent_or_size[second];parent_or_size[second]=first;_component_count--;returntrue;}boolundo(){if(history.empty())returnfalse;constHistoryEntryentry=history.back();history.pop_back();if(entry.first==-1)returntrue;parent_or_size[entry.first]=entry.first_value;parent_or_size[entry.second]=entry.second_value;_component_count++;returntrue;}intsnapshot()const{returnhistory_size();}voidrollback(intstate){assert(0<=state&&state<=history_size());while(history_size()>state)undo();}std::vector<std::vector<int>>groups()const{std::vector<int>leader_buffer(_n);std::vector<int>group_sizes(_n,0);for(intvertex=0;vertex<_n;vertex++){leader_buffer[vertex]=leader(vertex);group_sizes[leader_buffer[vertex]]++;}std::vector<std::vector<int>>result(_n);for(intvertex=0;vertex<_n;vertex++){result[vertex].reserve(group_sizes[vertex]);}for(intvertex=0;vertex<_n;vertex++){result[leader_buffer[vertex]].push_back(vertex);}result.erase(std::remove_if(result.begin(),result.end(),[](conststd::vector<int>&group){returngroup.empty();}),result.end());returnresult;}};}// namespace ds}// namespace m1une#line 10 "ds/dynamic_connectivity/offline_dynamic_connectivity.hpp"
namespacem1une{namespaceds{structOfflineDynamicConnectivity{private:structEdge{intu;intv;intbegin;intend;boolalive;};structQuery{intu;intv;inttime;};int_n;int_time=0;std::vector<Edge>_edges;std::vector<Query>_queries;voiddfs(conststd::vector<int>&offset,conststd::vector<std::pair<int,int>>&stored_edges,conststd::vector<int>&query_at,std::vector<bool>&answer,RollbackDsu&dsu,intnode,intbase)const{intsnapshot=dsu.snapshot();for(inti=offset[node];i<offset[node+1];i++){auto[u,v]=stored_edges[i];dsu.merge(u,v);}if(node>=base){intquery_id=query_at[node-base];if(query_id!=-1){constQuery&query=_queries[query_id];answer[query_id]=dsu.same(query.u,query.v);}}else{dfs(offset,stored_edges,query_at,answer,dsu,2*node,base);dfs(offset,stored_edges,query_at,answer,dsu,2*node+1,base);}dsu.rollback(snapshot);}public:OfflineDynamicConnectivity():OfflineDynamicConnectivity(0){}explicitOfflineDynamicConnectivity(intn):_n(n){assert(0<=n);}intsize()const{return_n;}intedge_count()const{returnint(_edges.size());}intquery_count()const{returnint(_queries.size());}intoperation_count()const{return_time;}voidreserve_edges(intcount){assert(0<=count);_edges.reserve(count);}voidreserve_queries(intcount){assert(0<=count);_queries.reserve(count);}booledge_alive(intedge_id)const{assert(0<=edge_id&&edge_id<int(_edges.size()));return_edges[edge_id].alive;}intadd_edge(intu,intv){assert(0<=u&&u<_n);assert(0<=v&&v<_n);intedge_id=int(_edges.size());_edges.push_back(Edge{u,v,_time,-1,true});_time++;returnedge_id;}boolerase_edge(intedge_id){assert(0<=edge_id&&edge_id<int(_edges.size()));Edge&edge=_edges[edge_id];if(!edge.alive)returnfalse;edge.end=_time;edge.alive=false;_time++;returntrue;}intadd_query(intu,intv){assert(0<=u&&u<_n);assert(0<=v&&v<_n);intquery_id=int(_queries.size());_queries.push_back(Query{u,v,_time});_time++;returnquery_id;}std::vector<bool>solve()const{std::vector<bool>answer(_queries.size(),false);if(_queries.empty())returnanswer;if(_edges.empty()){for(intquery_id=0;query_id<int(_queries.size());query_id++){answer[query_id]=_queries[query_id].u==_queries[query_id].v;}returnanswer;}intbase=1;while(base<_time)base*=2;intnode_count=2*base;std::vector<int>count(node_count,0);for(constEdge&edge:_edges){intend=edge.alive?_time:edge.end;if(edge.begin<end&&edge.u!=edge.v){intleft=edge.begin+base;intright=end+base;while(left<right){if(left&1)count[left++]++;if(right&1)count[--right]++;left/=2;right/=2;}}}std::vector<int>offset(node_count+1,0);for(intnode=1;node<node_count;node++)offset[node+1]=offset[node]+count[node];std::vector<int>cursor=offset;std::vector<std::pair<int,int>>stored_edges(offset[node_count]);for(constEdge&edge:_edges){intend=edge.alive?_time:edge.end;if(edge.begin>=end||edge.u==edge.v)continue;intleft=edge.begin+base;intright=end+base;while(left<right){if(left&1)stored_edges[cursor[left]++]={edge.u,edge.v},left++;if(right&1)--right,stored_edges[cursor[right]++]={edge.u,edge.v};left/=2;right/=2;}}std::vector<int>query_at(base,-1);for(intquery_id=0;query_id<int(_queries.size());query_id++){query_at[_queries[query_id].time]=query_id;}RollbackDsudsu(_n);dsu.reserve_history(int(std::min<std::size_t>(_n,stored_edges.size())));dfs(offset,stored_edges,query_at,answer,dsu,1,base);returnanswer;}};}// namespace ds}// namespace m1une#line 1 "ds/dynamic_connectivity/online_dynamic_connectivity.hpp"
#line 9 "ds/dynamic_connectivity/online_dynamic_connectivity.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 "ds/dynamic_tree/link_cut_tree.hpp"
#line 5 "ds/dynamic_tree/link_cut_tree.hpp"
#include<concepts>
#line 9 "ds/dynamic_tree/link_cut_tree.hpp"
#line 1 "monoid/concept.hpp"
#line 5 "monoid/concept.hpp"
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 11 "ds/dynamic_tree/link_cut_tree.hpp"
namespacem1une{namespaceds{template<m1une::monoid::IsCommutativeGroupGroup>structLinkCutTree{usingT=typenameGroup::value_type;private:structNode{intleft=-1;intright=-1;intparent=-1;boolrev=false;intsize=1;intvirtual_size=0;intall_size=1;Tvalue=Group::id();Tprod=Group::id();Trev_prod=Group::id();Tvirtual_prod=Group::id();Tall_prod=Group::id();};structEdgeInfo{intu=-1;intv=-1;intnode=-1;boolalive=false;};std::vector<Node>_nodes;std::vector<EdgeInfo>_edges;std::vector<int>_path_buffer;staticTmake_node_value(constT&value,int){returnvalue;}staticTmake_node_value(T&&value,int){returnstd::move(value);}template<classU>requires(!std::same_as<U,T>)&&(requires(Ux){Group::make(x);}||requires(Ux,inti){Group::make(x,i);}||std::convertible_to<U,T>)staticTmake_node_value(constU&value,intindex){ifconstexpr(requires(Ux){Group::make(x);}){returnGroup::make(value);}elseifconstexpr(requires(Ux,inti){Group::make(x,i);}){returnGroup::make(value,index);}else{returnstatic_cast<T>(value);}}intchild_size(intnode)const{returnnode==-1?0:_nodes[node].size;}intchild_all_size(intnode)const{returnnode==-1?0:_nodes[node].all_size;}Tchild_prod(intnode)const{returnnode==-1?Group::id():_nodes[node].prod;}Tchild_rev_prod(intnode)const{returnnode==-1?Group::id():_nodes[node].rev_prod;}Tchild_all_prod(intnode)const{returnnode==-1?Group::id():_nodes[node].all_prod;}Tnode_subtree_prod(intnode)const{constNode&x=_nodes[node];returnGroup::op(x.value,x.virtual_prod);}intnode_subtree_size(intnode)const{return1+_nodes[node].virtual_size;}boolis_splay_root(intnode)const{intparent=_nodes[node].parent;returnparent==-1||(_nodes[parent].left!=node&&_nodes[parent].right!=node);}voidupdate(intnode){Node&x=_nodes[node];x.size=1+child_size(x.left)+child_size(x.right);x.all_size=1+x.virtual_size+child_all_size(x.left)+child_all_size(x.right);x.prod=Group::op(Group::op(child_prod(x.left),x.value),child_prod(x.right));x.rev_prod=Group::op(Group::op(child_rev_prod(x.right),x.value),child_rev_prod(x.left));x.all_prod=Group::op(Group::op(child_all_prod(x.left),x.value),Group::op(x.virtual_prod,child_all_prod(x.right)));}voidadd_virtual_child(intnode,intchild){if(child==-1)return;Node&x=_nodes[node];x.virtual_size+=_nodes[child].all_size;x.virtual_prod=Group::op(x.virtual_prod,_nodes[child].all_prod);}voidremove_virtual_child(intnode,intchild){if(child==-1)return;Node&x=_nodes[node];x.virtual_size-=_nodes[child].all_size;x.virtual_prod=Group::op(x.virtual_prod,Group::inv(_nodes[child].all_prod));}voidapply_reverse(intnode){if(node==-1)return;Node&x=_nodes[node];std::swap(x.left,x.right);std::swap(x.prod,x.rev_prod);x.rev=!x.rev;}voidpush(intnode){if(node==-1||!_nodes[node].rev)return;apply_reverse(_nodes[node].left);apply_reverse(_nodes[node].right);_nodes[node].rev=false;}voidpush_to(intnode){_path_buffer.clear();intcur=node;_path_buffer.push_back(cur);while(!is_splay_root(cur)){cur=_nodes[cur].parent;_path_buffer.push_back(cur);}for(inti=int(_path_buffer.size())-1;i>=0;i--)push(_path_buffer[i]);}voidrotate(intnode){intparent=_nodes[node].parent;intgrand=_nodes[parent].parent;boolis_right=_nodes[parent].right==node;intmiddle=is_right?_nodes[node].left:_nodes[node].right;if(!is_splay_root(parent)){if(_nodes[grand].left==parent){_nodes[grand].left=node;}else{_nodes[grand].right=node;}}_nodes[node].parent=grand;if(is_right){_nodes[node].left=parent;_nodes[parent].right=middle;}else{_nodes[node].right=parent;_nodes[parent].left=middle;}if(middle!=-1)_nodes[middle].parent=parent;_nodes[parent].parent=node;update(parent);update(node);}voidsplay(intnode){push_to(node);while(!is_splay_root(node)){intparent=_nodes[node].parent;intgrand=_nodes[parent].parent;if(!is_splay_root(parent)){boolzig_zig=(_nodes[parent].left==node)==(_nodes[grand].left==parent);rotate(zig_zig?parent:node);}rotate(node);}}intaccess(intnode){intlast=-1;for(intcur=node;cur!=-1;cur=_nodes[cur].parent){splay(cur);add_virtual_child(cur,_nodes[cur].right);remove_virtual_child(cur,last);_nodes[cur].right=last;if(last!=-1)_nodes[last].parent=cur;update(cur);last=cur;}splay(node);returnlast;}voidcheck_vertex(intv)const{assert(0<=v&&v<int(_nodes.size()));}voidcheck_edge(intedge_id)const{assert(0<=edge_id&&edge_id<int(_edges.size()));}public:LinkCutTree()=default;explicitLinkCutTree(intn){assert(0<=n);_nodes.reserve(n);for(inti=0;i<n;i++)add_vertex();}explicitLinkCutTree(conststd::vector<T>&values){_nodes.reserve(values.size());for(inti=0;i<int(values.size());i++)add_vertex(values[i]);}explicitLinkCutTree(std::vector<T>&&values){_nodes.reserve(values.size());for(inti=0;i<int(values.size());i++)add_vertex(std::move(values[i]));}template<classU>requires(!std::same_as<U,T>)&&(requires(Ux){Group::make(x);}||requires(Ux,inti){Group::make(x,i);}||std::convertible_to<U,T>)explicitLinkCutTree(conststd::vector<U>&values){_nodes.reserve(values.size());for(inti=0;i<int(values.size());i++)add_vertex(make_node_value(values[i],i));}intsize()const{returnint(_nodes.size());}boolempty()const{return_nodes.empty();}intadd_vertex(constT&value=Group::id()){Nodenode;node.value=value;node.prod=value;node.rev_prod=value;node.all_prod=value;_nodes.push_back(std::move(node));returnint(_nodes.size())-1;}intadd_vertex(T&&value){Nodenode;node.value=std::move(value);node.prod=node.value;node.rev_prod=node.value;node.all_prod=node.value;_nodes.push_back(std::move(node));returnint(_nodes.size())-1;}template<classU>requires(!std::same_as<std::remove_cvref_t<U>,T>)&&(requires(Ux){Group::make(x);}||requires(Ux,inti){Group::make(x,i);}||std::convertible_to<U,T>)intadd_vertex(constU&value){returnadd_vertex(make_node_value(value,size()));}intedge_count()const{returnint(_edges.size());}booledge_alive(intedge_id)const{check_edge(edge_id);return_edges[edge_id].alive;}intedge_node(intedge_id)const{check_edge(edge_id);return_edges[edge_id].node;}std::pair<int,int>edge_endpoints(intedge_id)const{check_edge(edge_id);return{_edges[edge_id].u,_edges[edge_id].v};}constT&get(intv)const{check_vertex(v);return_nodes[v].value;}constT&operator[](intv)const{returnget(v);}voidset(intv,constT&value){check_vertex(v);access(v);_nodes[v].value=value;update(v);}voidset(intv,T&&value){check_vertex(v);access(v);_nodes[v].value=std::move(value);update(v);}template<classU>requires(!std::same_as<std::remove_cvref_t<U>,T>)&&(requires(Ux){Group::make(x);}||requires(Ux,inti){Group::make(x,i);}||std::convertible_to<U,T>)voidset(intv,constU&value){set(v,make_node_value(value,v));}// Makes `v` the represented root of its component.voidevert(intv){check_vertex(v);access(v);apply_reverse(v);}// Alias for `evert(v)`; changes the represented root to `v`.voidreroot(intv){evert(v);}// Returns the current represented root of `v`'s component.intcomponent_root(intv){check_vertex(v);access(v);intcur=v;push(cur);while(_nodes[cur].left!=-1){cur=_nodes[cur].left;push(cur);}splay(cur);returncur;}// Alias for `component_root(v)`.introot(intv){returncomponent_root(v);}boolconnected(intu,intv){check_vertex(u);check_vertex(v);if(u==v)returntrue;returncomponent_root(u)==component_root(v);}boolsame(intu,intv){returnconnected(u,v);}// Links two components. Internally calls `evert(u)`, so the represented root may change.boollink(intu,intv){check_vertex(u);check_vertex(v);if(u==v)returnfalse;evert(u);if(component_root(v)==u)returnfalse;access(v);_nodes[u].parent=v;add_virtual_child(v,u);update(v);returntrue;}// Links `child` under `parent`. This is the same operation as `link(child, parent)`;// it internally calls `evert(child)`, so that side's represented root may change.boollink_parent(intchild,intparent){returnlink(child,parent);}intlink_edge(intu,intv,constT&value=Group::id()){check_vertex(u);check_vertex(v);if(u==v||connected(u,v))return-1;intedge_id=int(_edges.size());intnode=add_vertex(value);_edges.push_back(EdgeInfo{u,v,node,true});boolok1=link(u,node);boolok2=link(node,v);assert(ok1&&ok2);returnedge_id;}intlink_edge(intu,intv,T&&value){check_vertex(u);check_vertex(v);if(u==v||connected(u,v))return-1;intedge_id=int(_edges.size());intnode=add_vertex(std::move(value));_edges.push_back(EdgeInfo{u,v,node,true});boolok1=link(u,node);boolok2=link(node,v);assert(ok1&&ok2);returnedge_id;}template<classU>requires(!std::same_as<std::remove_cvref_t<U>,T>)&&(requires(Ux){Group::make(x);}||requires(Ux,inti){Group::make(x,i);}||std::convertible_to<U,T>)intlink_edge(intu,intv,constU&value){check_vertex(u);check_vertex(v);if(u==v||connected(u,v))return-1;returnlink_edge(u,v,make_node_value(value,size()));}// Cuts edge `(u, v)`. Internally calls `evert(u)`, so the represented root may change.boolcut(intu,intv){check_vertex(u);check_vertex(v);if(u==v)returnfalse;evert(u);access(v);if(_nodes[v].left!=u||_nodes[u].right!=-1)returnfalse;_nodes[v].left=-1;_nodes[u].parent=-1;update(v);returntrue;}// Cuts the parent edge of `v` in the current represented-root orientation.// Unlike `cut(u, v)`, this does not call `evert`.boolcut_parent(intv){check_vertex(v);access(v);intleft=_nodes[v].left;if(left==-1)returnfalse;_nodes[v].left=-1;_nodes[left].parent=-1;update(v);returntrue;}boolcut_edge(intedge_id){check_edge(edge_id);EdgeInfo&edge=_edges[edge_id];if(!edge.alive)returnfalse;boolok1=cut(edge.u,edge.node);boolok2=cut(edge.node,edge.v);if(ok1&&ok2)edge.alive=false;returnok1&&ok2;}constT&get_edge(intedge_id)const{returnget(edge_node(edge_id));}voidset_edge(intedge_id,constT&value){set(edge_node(edge_id),value);}voidset_edge(intedge_id,T&&value){set(edge_node(edge_id),std::move(value));}template<classU>requires(!std::same_as<std::remove_cvref_t<U>,T>)&&(requires(Ux){Group::make(x);}||requires(Ux,inti){Group::make(x,i);}||std::convertible_to<U,T>)voidset_edge(intedge_id,constU&value){set(edge_node(edge_id),make_node_value(value,edge_node(edge_id)));}// Returns the path product from `u` to `v`. Internally calls `evert(u)`,// so the represented root may change.Tprod(intu,intv){check_vertex(u);check_vertex(v);assert(connected(u,v));evert(u);access(v);return_nodes[v].prod;}// Alias for `prod(u, v)`. Internally calls `evert(u)`,// so the represented root may change.Tpath_prod(intu,intv){returnprod(u,v);}// Returns the number of vertices on path `u`-`v`. Internally calls `evert(u)`,// so the represented root may change.intpath_size(intu,intv){check_vertex(u);check_vertex(v);assert(connected(u,v));evert(u);access(v);return_nodes[v].size;}// Returns the `k`-th vertex on path `u`-`v`. Internally calls `evert(u)`,// so the represented root may change.intkth_vertex(intu,intv,intk){check_vertex(u);check_vertex(v);assert(connected(u,v));evert(u);access(v);assert(0<=k&&k<_nodes[v].size);intcur=v;while(true){push(cur);intleft_size=child_size(_nodes[cur].left);if(k<left_size){cur=_nodes[cur].left;}elseif(k==left_size){splay(cur);returncur;}else{k-=left_size+1;cur=_nodes[cur].right;}}}intlca(intu,intv){check_vertex(u);check_vertex(v);if(!connected(u,v))return-1;if(u==v)returnu;access(u);returnaccess(v);}// Returns the aggregate of `v`'s subtree when the represented tree is rooted at `root`.// Internally calls `evert(root)`, so the represented root may change.Tsubtree_prod(introot,intv){check_vertex(root);check_vertex(v);assert(connected(root,v));evert(root);access(v);returnnode_subtree_prod(v);}// Returns the aggregate of `v`'s subtree with respect to the current represented root.Tsubtree_prod(intv){check_vertex(v);access(v);returnnode_subtree_prod(v);}// Returns the size of `v`'s subtree when the represented tree is rooted at `root`.// Internally calls `evert(root)`, so the represented root may change.intsubtree_size(introot,intv){check_vertex(root);check_vertex(v);assert(connected(root,v));evert(root);access(v);returnnode_subtree_size(v);}// Returns the size of `v`'s subtree with respect to the current represented root.intsubtree_size(intv){check_vertex(v);access(v);returnnode_subtree_size(v);}// Returns the aggregate of the whole connected component containing `v`.Tcomponent_prod(intv){intr=root(v);returnsubtree_prod(r,r);}// Returns the number of vertices in the connected component containing `v`.intcomponent_size(intv){intr=root(v);returnsubtree_size(r,r);}// Returns the child of `root` that lies on path `root`-`v`.intchild_toward(introot,intv){check_vertex(root);check_vertex(v);assert(root!=v);assert(connected(root,v));returnkth_vertex(root,v,1);}// Returns the aggregate of the entire branch of `root` that contains `v`.Tbranch_prod(introot,intv){check_vertex(root);check_vertex(v);assert(root!=v);intchild=child_toward(root,v);returnsubtree_prod(root,child);}// Returns the size of the entire branch of `root` that contains `v`.intbranch_size(introot,intv){check_vertex(root);check_vertex(v);assert(root!=v);intchild=child_toward(root,v);returnsubtree_size(root,child);}// Returns the parent of `v` when rooted at `root`, or `-1` if `v == root`.intparent(introot,intv){check_vertex(root);check_vertex(v);if(root==v)return-1;assert(connected(root,v));intd=path_size(root,v);assert(2<=d);returnkth_vertex(root,v,d-2);}// Returns `v`'s rooted subtree aggregate excluding the child-side subtree.Tsubtree_prod_excluding_child(introot,intv,intchild){check_vertex(root);check_vertex(v);check_vertex(child);assert(parent(root,child)==v);Twhole=subtree_prod(root,v);Tsub=subtree_prod(root,child);returnGroup::op(whole,Group::inv(sub));}// Returns `v`'s rooted subtree size excluding the child-side subtree.intsubtree_size_excluding_child(introot,intv,intchild){check_vertex(root);check_vertex(v);check_vertex(child);assert(parent(root,child)==v);returnsubtree_size(root,v)-subtree_size(root,child);}};}// namespace ds}// namespace m1une#line 12 "ds/dynamic_connectivity/online_dynamic_connectivity.hpp"
namespacem1une{namespaceds{structOnlineDynamicConnectivity{private:usingForest=LinkCutTree<m1une::monoid::Add<int>>;structEdge{intu;intv;boolalive;booltree;intprevious_u=-1;intnext_u=-1;intprevious_v=-1;intnext_v=-1;};int_n;int_component_count;int_active_edge_count=0;Forest_forest;std::vector<Edge>_edges;std::vector<int>_tree_head;std::vector<int>_non_tree_head;std::vector<std::uint32_t>_visited;std::vector<std::uint32_t>_edge_visited;std::uint32_t_visit_token=0;std::vector<int>_stack;std::vector<int>_component;intendpoint_side(constEdge&edge,intv)const{returnedge.u==v?0:1;}int&previous(Edge&edge,intside){returnside==0?edge.previous_u:edge.previous_v;}int&next(Edge&edge,intside){returnside==0?edge.next_u:edge.next_v;}intnext(constEdge&edge,intside)const{returnside==0?edge.next_u:edge.next_v;}voidinsert_one(std::vector<int>&head,intedge_id,intv,intside){Edge&edge=_edges[edge_id];intold_head=head[v];previous(edge,side)=-1;next(edge,side)=old_head;if(old_head!=-1){Edge&old_edge=_edges[old_head];previous(old_edge,endpoint_side(old_edge,v))=edge_id;}head[v]=edge_id;}voiderase_one(std::vector<int>&head,intedge_id,intv,intside){Edge&edge=_edges[edge_id];intprevious_id=previous(edge,side);intnext_id=next(edge,side);if(previous_id==-1){head[v]=next_id;}else{Edge&previous_edge=_edges[previous_id];next(previous_edge,endpoint_side(previous_edge,v))=next_id;}if(next_id!=-1){Edge&next_edge=_edges[next_id];previous(next_edge,endpoint_side(next_edge,v))=previous_id;}previous(edge,side)=-1;next(edge,side)=-1;}voidinsert_incident(std::vector<int>&head,intedge_id){constEdge&edge=_edges[edge_id];intu=edge.u;intv=edge.v;insert_one(head,edge_id,u,0);if(u!=v)insert_one(head,edge_id,v,1);}voiderase_incident(std::vector<int>&head,intedge_id){constEdge&edge=_edges[edge_id];intu=edge.u;intv=edge.v;erase_one(head,edge_id,u,0);if(u!=v)erase_one(head,edge_id,v,1);}voidmake_tree_edge(intedge_id){Edge&edge=_edges[edge_id];assert(edge.alive&&!edge.tree&&edge.u!=edge.v);erase_incident(_non_tree_head,edge_id);boollinked=_forest.link(edge.u,edge.v);assert(linked);edge.tree=true;insert_incident(_tree_head,edge_id);_component_count--;}voidcollect_component(intstart){_visit_token++;if(_visit_token==0){std::fill(_visited.begin(),_visited.end(),0);std::fill(_edge_visited.begin(),_edge_visited.end(),0);_visit_token=1;}_stack.clear();_component.clear();_visited[start]=_visit_token;_stack.push_back(start);while(!_stack.empty()){intv=_stack.back();_stack.pop_back();_component.push_back(v);for(intedge_id=_tree_head[v];edge_id!=-1;){constEdge&edge=_edges[edge_id];intedge_side=endpoint_side(edge,v);edge_id=next(edge,edge_side);intto=edge.u^edge.v^v;if(_visited[to]==_visit_token)continue;_visited[to]=_visit_token;_stack.push_back(to);}}}voidreconnect(intu,intv){intstart=_forest.component_size(u)<=_forest.component_size(v)?u:v;collect_component(start);intreplacement=-1;for(intx:_component){for(intedge_id=_non_tree_head[x];edge_id!=-1;){constEdge&edge=_edges[edge_id];intedge_side=endpoint_side(edge,x);intcurrent_edge=edge_id;edge_id=next(edge,edge_side);if(_edge_visited[current_edge]==_visit_token)continue;_edge_visited[current_edge]=_visit_token;if(_visited[edge.u]!=_visit_token||_visited[edge.v]!=_visit_token){replacement=current_edge;break;}}if(replacement!=-1)break;}if(replacement!=-1)make_tree_edge(replacement);}public:OnlineDynamicConnectivity():OnlineDynamicConnectivity(0){}explicitOnlineDynamicConnectivity(intn):_n(n),_component_count(n),_forest(n),_tree_head(n,-1),_non_tree_head(n,-1),_visited(n,0){assert(0<=n);}intsize()const{return_n;}intedge_count()const{returnint(_edges.size());}intactive_edge_count()const{return_active_edge_count;}intcomponent_count()const{return_component_count;}voidreserve_edges(intcount){assert(0<=count);_edges.reserve(count);_edge_visited.reserve(count);}booledge_alive(intedge_id)const{assert(0<=edge_id&&edge_id<int(_edges.size()));return_edges[edge_id].alive;}std::pair<int,int>edge_endpoints(intedge_id)const{assert(0<=edge_id&&edge_id<int(_edges.size()));return{_edges[edge_id].u,_edges[edge_id].v};}boolconnected(intu,intv){assert(0<=u&&u<_n);assert(0<=v&&v<_n);return_forest.connected(u,v);}boolsame(intu,intv){returnconnected(u,v);}intcomponent_size(intv){assert(0<=v&&v<_n);return_forest.component_size(v);}intadd_edge(intu,intv){assert(0<=u&&u<_n);assert(0<=v&&v<_n);boolis_tree=u!=v&&_forest.link(u,v);intedge_id=int(_edges.size());Edgeedge;edge.u=u;edge.v=v;edge.alive=true;edge.tree=is_tree;_edges.push_back(edge);_edge_visited.push_back(0);_active_edge_count++;if(is_tree){insert_incident(_tree_head,edge_id);_component_count--;}else{insert_incident(_non_tree_head,edge_id);}returnedge_id;}boolerase_edge(intedge_id){assert(0<=edge_id&&edge_id<int(_edges.size()));Edge&edge=_edges[edge_id];if(!edge.alive)returnfalse;edge.alive=false;_active_edge_count--;if(!edge.tree){erase_incident(_non_tree_head,edge_id);returntrue;}erase_incident(_tree_head,edge_id);boolcut=_forest.cut(edge.u,edge.v);assert(cut);_component_count++;reconnect(edge.u,edge.v);returntrue;}};}// namespace ds}// namespace m1une#line 6 "ds/dynamic_connectivity/all.hpp"
#line 11 "verify/ds/dynamic_connectivity/dynamic_connectivity.test.cpp"
structNaiveDynamicGraph{structEdge{intu;intv;boolalive;};intn;std::vector<Edge>edges;explicitNaiveDynamicGraph(intn):n(n){}intadd_edge(intu,intv){intid=int(edges.size());edges.push_back(Edge{u,v,true});returnid;}boolerase_edge(intid){if(!edges[id].alive)returnfalse;edges[id].alive=false;returntrue;}std::vector<int>component(intstart)const{std::vector<std::vector<int>>graph(n);for(constEdge&edge:edges){if(!edge.alive||edge.u==edge.v)continue;graph[edge.u].push_back(edge.v);graph[edge.v].push_back(edge.u);}std::vector<int>visited(n,false);std::queue<int>queue;std::vector<int>vertices;visited[start]=true;queue.push(start);while(!queue.empty()){intv=queue.front();queue.pop();vertices.push_back(v);for(intto:graph[v]){if(visited[to])continue;visited[to]=true;queue.push(to);}}returnvertices;}boolconnected(intu,intv)const{std::vector<int>vertices=component(u);for(intx:vertices){if(x==v)returntrue;}returnfalse;}intcomponent_count()const{std::vector<bool>visited(n,false);intresult=0;for(intv=0;v<n;v++){if(visited[v])continue;result++;for(intx:component(v))visited[x]=true;}returnresult;}};voidtest_online_basic(){m1une::ds::OnlineDynamicConnectivitygraph(4);graph.reserve_edges(8);inte01=graph.add_edge(0,1);inte12=graph.add_edge(1,2);inte02=graph.add_edge(0,2);intloop=graph.add_edge(3,3);assert(graph.connected(0,2));assert(graph.component_size(0)==3);assert(graph.component_count()==2);assert(graph.active_edge_count()==4);assert(graph.erase_edge(e12));assert(graph.connected(0,2));assert(graph.erase_edge(e02));assert(!graph.connected(0,2));assert(graph.component_count()==3);assert(!graph.erase_edge(e02));assert(graph.erase_edge(loop));assert(graph.erase_edge(e01));assert(graph.component_count()==4);}voidtest_offline_basic(){m1une::ds::OfflineDynamicConnectivitygraph(3);graph.reserve_edges(8);graph.reserve_queries(8);inte01=graph.add_edge(0,1);intq0=graph.add_query(0,2);inte12=graph.add_edge(1,2);intq1=graph.add_query(0,2);assert(graph.erase_edge(e01));intq2=graph.add_query(0,2);assert(!graph.erase_edge(e01));intparallel=graph.add_edge(1,2);intq3=graph.add_query(1,2);assert(graph.erase_edge(e12));intq4=graph.add_query(1,2);assert(graph.erase_edge(parallel));intq5=graph.add_query(1,2);std::vector<bool>answer=graph.solve();assert(!answer[q0]);assert(answer[q1]);assert(!answer[q2]);assert(answer[q3]);assert(answer[q4]);assert(!answer[q5]);assert(answer==graph.solve());intrestored=graph.add_edge(0,2);intq6=graph.add_query(0,2);answer=graph.solve();assert(answer[q6]);assert(graph.erase_edge(restored));}voidtest_online_random(){std::mt19937random(123456789);for(inttest=0;test<80;test++){intn=1+random()%15;m1une::ds::OnlineDynamicConnectivitygraph(n);NaiveDynamicGraphnaive(n);std::vector<int>active;for(intoperation=0;operation<1000;operation++){inttype=random()%5;if(type<=1||active.empty()){intu=random()%n;intv=random()%n;intid=graph.add_edge(u,v);assert(id==naive.add_edge(u,v));active.push_back(id);}elseif(type==2){intindex=random()%active.size();intid=active[index];std::swap(active[index],active.back());active.pop_back();assert(graph.erase_edge(id));assert(naive.erase_edge(id));}else{intu=random()%n;intv=random()%n;assert(graph.connected(u,v)==naive.connected(u,v));assert(graph.component_size(u)==int(naive.component(u).size()));}assert(graph.active_edge_count()==int(active.size()));assert(graph.component_count()==naive.component_count());}}}voidtest_offline_random(){std::mt19937random(987654321);for(inttest=0;test<100;test++){intn=1+random()%12;m1une::ds::OfflineDynamicConnectivitygraph(n);NaiveDynamicGraphnaive(n);std::vector<int>active;std::vector<bool>expected;for(intoperation=0;operation<500;operation++){inttype=random()%4;if(type==0||active.empty()){intu=random()%n;intv=random()%n;intid=graph.add_edge(u,v);assert(id==naive.add_edge(u,v));active.push_back(id);}elseif(type==1){intindex=random()%active.size();intid=active[index];std::swap(active[index],active.back());active.pop_back();assert(graph.erase_edge(id));assert(naive.erase_edge(id));}else{intu=random()%n;intv=random()%n;assert(graph.add_query(u,v)==int(expected.size()));expected.push_back(naive.connected(u,v));}}assert(graph.solve()==expected);}}intmain(){m1une::utilities::FastInputfast_input;m1une::utilities::FastOutputfast_output;test_online_basic();test_offline_basic();test_online_random();test_offline_random();longlonga,b;fast_input>>a>>b;fast_output<<a+b<<'\n';}