#line 1 "verify/graph/general_weighted_matching.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/general_weighted_matching"
#line 1 "graph/general_weighted_matching.hpp"
#include<algorithm>
#include<cassert>
#include<cstddef>
#include<functional>
#include<limits>
#include<queue>
#include<type_traits>
#include<utility>
#include<vector>#line 1 "graph/graph.hpp"
#include<array>
#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 15 "graph/general_weighted_matching.hpp"
namespacem1une{namespacegraph{namespaceinternal{// Primal-dual weighted blossom algorithm using Gabow's event queues.// Reference: H. N. Gabow, "Data Structures for Weighted Matching and// Extensions to b-matching and f-factors", 2016.// Vertices 1..n are atoms; larger indices represent contracted blossoms.template<classCost,classTotalCost>classWeightedBlossomSolver{public:usingcost_type=Cost;usingtotal_type=TotalCost;private:enumBlossomLabel:int{separated_label=-2,inner_label=-1,free_label=0,outer_label=1};staticconstexprcost_typeinfinity=cost_type(1)<<(sizeof(cost_type)*8-2);template<classT>classMutableBinaryHeap{public:structNode{booloperator<(constNode&rhs)const{if(value<rhs.value){returntrue;}if(rhs.value<value){returnfalse;}returnid<rhs.id;}Tvalue;intid;};MutableBinaryHeap()=default;explicitMutableBinaryHeap(intcapacity):_size(0),_nodes(capacity+1),_position(capacity,0){}boolempty()const{return_size==0;}voidclear(){while(_size>0){_position[_nodes[_size].id]=0;_size--;}}Tmin()const{return_nodes[1].value;}intargmin()const{return_nodes[1].id;}voidpop(){if(_size>0)pop(1);}voiderase(intid){if(_position[id])pop(_position[id]);}boolhas(intid)const{return_position[id]!=0;}voidupdate(intid,Tv){if(!has(id))returnpush(id,v);boolup=(v<_nodes[_position[id]].value);_nodes[_position[id]].value=v;if(up){up_heap(_position[id]);}else{down_heap(_position[id]);}}voiddecrease_key(intid,Tv){if(!has(id))returnpush(id,v);if(v<_nodes[_position[id]].value){_nodes[_position[id]].value=v;up_heap(_position[id]);}}voidpush(intid,Tv){_position[id]=++_size;_nodes[_size]={v,id};up_heap(_size);}private:voidpop(intpos){_position[_nodes[pos].id]=0;if(pos==_size){--_size;return;}boolup=(_nodes[_size].value<_nodes[pos].value);_nodes[pos]=_nodes[_size--];_position[_nodes[pos].id]=pos;if(up){up_heap(pos);}else{down_heap(pos);}}voidswap_node(inta,intb){std::swap(_nodes[a],_nodes[b]);_position[_nodes[a].id]=a;_position[_nodes[b].id]=b;}voiddown_heap(intpos){for(intcurrent=pos;;){intnext=current;if(2*current<=_size&&_nodes[2*current]<_nodes[next]){next=2*current;}if(2*current+1<=_size&&_nodes[2*current+1]<_nodes[next]){next=2*current+1;}if(next==current)break;swap_node(current,next);current=next;}}voidup_heap(intpos){for(intcurrent=pos;current>1&&_nodes[current]<_nodes[current>>1];current>>=1){swap_node(current,current>>1);}}int_size;std::vector<Node>_nodes;std::vector<int>_position;};template<classKey>classDisjointPairingHeaps{private:structNode{Node():key(),child(0),next(0),prev(-1){}explicitNode(Keyvalue):key(value),child(0),next(0),prev(0){}Keykey;intchild;intnext;intprev;};public:DisjointPairingHeaps(intheap_count,intnode_count):_roots(heap_count),_nodes(node_count){}voidclear(inth){if(_roots[h]){clear_rec(_roots[h]);_roots[h]=0;}}boolempty(inth)const{return!_roots[h];}boolused(intv)const{return_nodes[v].prev>=0;}Keymin(inth)const{return_nodes[_roots[h]].key;}voidpush(inth,intv,Keykey){_nodes[v]=Node(key);_roots[h]=merge(_roots[h],v);}voiderase(inth,intv){if(!used(v))return;intw=two_pass_pairing(_nodes[v].child);if(!_nodes[v].prev){_roots[h]=w;}else{cut(v);_roots[h]=merge(_roots[h],w);}_nodes[v].prev=-1;}voiddecrease_key(inth,intv,Keykey){if(!used(v))returnpush(h,v,key);if(!_nodes[v].prev){_nodes[v].key=key;}else{cut(v);_nodes[v].key=key;_roots[h]=merge(_roots[h],v);}}private:voidclear_rec(intv){for(;v;v=_nodes[v].next){if(_nodes[v].child)clear_rec(_nodes[v].child);_nodes[v].prev=-1;}}inlinevoidcut(intv){auto&n=_nodes[v];intprevious=n.prev;intnext=n.next;auto&previous_node=_nodes[previous];if(previous_node.child==v){previous_node.child=next;}else{previous_node.next=next;}_nodes[next].prev=previous;n.next=n.prev=0;}intmerge(intl,intr){if(!l)returnr;if(!r)returnl;if(_nodes[l].key>_nodes[r].key)std::swap(l,r);intlc=_nodes[r].next=_nodes[l].child;_nodes[l].child=_nodes[lc].prev=r;return_nodes[r].prev=l;}inttwo_pass_pairing(introot){if(!root)return0;inta=root;root=0;while(a){intb=_nodes[a].next;intnext_a=0;_nodes[a].prev=_nodes[a].next=0;if(b){next_a=_nodes[b].next;_nodes[b].prev=_nodes[b].next=0;}a=merge(a,b);_nodes[a].next=root;root=a;a=next_a;}ints=_nodes[root].next;_nodes[root].next=0;while(s){intt=_nodes[s].next;_nodes[s].next=0;root=merge(root,s);s=t;}returnroot;}private:std::vector<int>_roots;std::vector<Node>_nodes;};template<classT>structReservablePriorityQueue:publicstd::priority_queue<T,std::vector<T>,std::greater<T>>{ReservablePriorityQueue()=default;explicitReservablePriorityQueue(intcapacity){this->c.reserve(capacity);}Tmin()const{returnthis->top();}voidclear(){this->c.clear();}};template<classT>structFixedQueue{FixedQueue()=default;explicitFixedQueue(intcapacity):_head(0),_tail(0),_data(capacity){}voidenqueue(intu){_data[_tail++]=u;}intdequeue(){return_data[_head++];}boolempty()const{return_head==_tail;}voidclear(){_head=_tail=0;}int_head=0;int_tail=0;std::vector<T>_data;};public:structInputEdge{intfrom;intto;cost_typecost;};private:structSolverEdge{intto;cost_typecost;};structBlossomLink{intfrom;intto;};structBlossomNode{structCycleLink{intblossom;intvertex;};BlossomNode()=default;explicitBlossomNode(intvertex):parent(0),size(1){cycle[0]=cycle[1]=CycleLink{vertex,vertex};}intnext_v()const{returncycle[0].vertex;}intnext_b()const{returncycle[0].blossom;}intprev_v()const{returncycle[1].vertex;}intprev_b()const{returncycle[1].blossom;}intparent=0;intsize=0;CycleLinkcycle[2];};structVertexEvent{VertexEvent()=default;VertexEvent(cost_typeevent_time,intvertex):time(event_time),id(vertex){}booloperator<(constVertexEvent&rhs)const{if(time<rhs.time){returntrue;}if(rhs.time<time){returnfalse;}returnid<rhs.id;}booloperator>(constVertexEvent&rhs)const{returnrhs<*this;}cost_typetime=cost_type();intid=0;};structEdgeEvent{EdgeEvent()=default;EdgeEvent(cost_typeevent_time,intfrom_,intto_):time(event_time),from(from_),to(to_){}booloperator<(constEdgeEvent&rhs)const{if(time<rhs.time){returntrue;}if(time>rhs.time){returnfalse;}returnstd::make_pair(from,to)<std::make_pair(rhs.from,rhs.to);}booloperator>(constEdgeEvent&rhs)const{returnrhs<*this;}cost_typetime=cost_type();intfrom=0;intto=0;};public:WeightedBlossomSolver(intn,conststd::vector<InputEdge>&input_edges):_vertex_count(n),_blossom_count((n-1)/2),_state_count(n+_blossom_count+1),_offset(n+2),_edges(input_edges.size()*2),_grow_heap(_state_count),_blossom_grow_heaps(_state_count,_state_count),_contract_heap(int(_edges.size())),_expand_heap(_state_count){for(constInputEdge&edge:input_edges){_offset[edge.from+1]++;_offset[edge.to+1]++;}for(inti=1;i<=_vertex_count+1;i++)_offset[i]+=_offset[i-1];for(constInputEdge&edge:input_edges){_edges[_offset[edge.from]++]=SolverEdge{edge.to,edge.cost*2};_edges[_offset[edge.to]++]=SolverEdge{edge.from,edge.cost*2};}for(inti=_vertex_count+1;i>0;i--)_offset[i]=_offset[i-1];_offset[0]=0;}total_typesolve(std::vector<std::pair<int,int>>&matching){initialize_state();initialize_potentials();for(intvertex=1;vertex<=_vertex_count;vertex++){if(_mate[vertex]==0)augment_from(vertex);}matching.clear();for(intvertex=1;vertex<=_vertex_count;vertex++){if(_mate[vertex]>vertex)matching.emplace_back(vertex,_mate[vertex]);}returncompute_matching_weight();}private:total_typecompute_matching_weight()const{total_typeresult=0;for(intvertex=1;vertex<=_vertex_count;vertex++){if(_mate[vertex]>vertex){cost_typebest_cost=0;for(intedge_id=_offset[vertex];edge_id<_offset[vertex+1];edge_id++){if(_edges[edge_id].to==_mate[vertex]){best_cost=std::max(best_cost,_edges[edge_id].cost);}}result+=best_cost;}}returnresult>>1;}total_typereduced_cost(intfrom,intto,constSolverEdge&edge)const{returntotal_type(_potential[from])+_potential[to]-edge.cost;}voidrematch(intvertex,intnew_mate){intold_mate=_mate[vertex];_mate[vertex]=new_mate;if(_mate[old_mate]!=vertex)return;if(_tree_link[vertex].to==_surface[_tree_link[vertex].to]){_mate[old_mate]=_tree_link[vertex].from;rematch(_mate[old_mate],old_mate);}else{intfrom=_tree_link[vertex].from;intto=_tree_link[vertex].to;rematch(from,to);rematch(to,from);}}voidrepair_matching(intblossom){if(blossom<=_vertex_count)return;intchild=_base[blossom];intfirst_vertex=_nodes[child].cycle[0].vertex;intfirst_neighbor=_nodes[child].cycle[0].blossom;intdirection=(_nodes[first_neighbor].cycle[1].vertex==_mate[first_vertex])?0:1;while(true){intmatched_vertex=_nodes[child].cycle[direction].vertex;intmatched_child=_nodes[child].cycle[direction].blossom;if(_nodes[matched_child].cycle[1^direction].vertex!=_mate[matched_vertex])break;repair_matching(child);repair_matching(matched_child);child=_nodes[matched_child].cycle[direction].blossom;}_base[blossom]=child;repair_matching(child);_mate[blossom]=_mate[child];}voidreset_clock(){_time=0;_vertex_event={infinity,0};}voidreset_blossom(intblossom){_label[blossom]=free_label;_tree_link[blossom].from=0;_slack[blossom]=infinity;_lazy[blossom]=0;}voidreset_search_state(){_label[0]=free_label;_tree_link[0].from=0;for(intvertex=1;vertex<=_vertex_count;vertex++){if(_label[vertex]==outer_label){_potential[vertex]-=_time;}else{intblossom=_surface[vertex];_potential[vertex]+=_lazy[blossom];if(_label[blossom]==inner_label){_potential[vertex]+=_time-_created_at[blossom];}}reset_blossom(vertex);}intremaining_blossoms=_blossom_count-_unused_count;for(intblossom=_vertex_count+1;remaining_blossoms>0&&blossom<_state_count;blossom++){if(_base[blossom]!=blossom){if(_surface[blossom]==blossom){repair_matching(blossom);if(_label[blossom]==outer_label){_potential[blossom]+=(_time-_created_at[blossom])<<1;}elseif(_label[blossom]==inner_label){materialize_potential<inner_label>(blossom);}else{materialize_potential<free_label>(blossom);}}_blossom_grow_heaps.clear(blossom);reset_blossom(blossom);remaining_blossoms--;}}_queue.clear();reset_clock();_grow_heap.clear();_contract_heap.clear();_expand_heap.clear();}voidaugment_from(introot){if(_potential[root]==0)return;link_blossom(_surface[root],{0,0});make_outer(_surface[root],0);for(boolaugmented=false;!augmented;){augmented=scan_tight_edges(root);if(augmented)break;augmented=advance_dual(root);}reset_search_state();}template<BlossomLabeltarget_label>cost_typematerialize_potential(intblossom){cost_typedelta=_lazy[blossom];_lazy[blossom]=0;if(target_label==inner_label){cost_typeelapsed=_time-_created_at[blossom];if(blossom>_vertex_count)_potential[blossom]-=elapsed<<1;delta+=elapsed;}returndelta;}template<BlossomLabeltarget_label>voidupdate_grow_event(intfrom,intto,intto_blossom,cost_typeslack){if(slack>=_slack[to])return;_slack[to]=slack;_best_from[to]=from;if(to==to_blossom){if(target_label!=inner_label){_grow_heap.decrease_key(to,EdgeEvent(slack+_lazy[to],from,to));}}else{intto_group=_group[to];if(to_group!=to){if(slack>=_slack[to_group])return;_slack[to_group]=slack;}_blossom_grow_heaps.decrease_key(to_blossom,to_group,EdgeEvent(slack,from,to));if(target_label==inner_label)return;EdgeEventevent=_blossom_grow_heaps.min(to_blossom);_grow_heap.decrease_key(to_blossom,EdgeEvent(event.time+_lazy[to_blossom],event.from,event.to));}}voidactivate_grow_event(intblossom){if(blossom<=_vertex_count){if(_slack[blossom]<infinity){_grow_heap.push(blossom,EdgeEvent(_slack[blossom]+_lazy[blossom],_best_from[blossom],blossom));}}else{if(_blossom_grow_heaps.empty(blossom))return;EdgeEventevent=_blossom_grow_heaps.min(blossom);_grow_heap.push(blossom,EdgeEvent(event.time+_lazy[blossom],event.from,event.to));}}voidswap_blossoms(inta,intb){// b is a maximal blossom.std::swap(_base[a],_base[b]);if(_base[a]==a)_base[a]=b;std::swap(_heavy[a],_heavy[b]);if(_heavy[a]==a)_heavy[a]=b;std::swap(_tree_link[a],_tree_link[b]);std::swap(_mate[a],_mate[b]);std::swap(_potential[a],_potential[b]);std::swap(_lazy[a],_lazy[b]);std::swap(_created_at[a],_created_at[b]);for(intdirection=0;direction<2;direction++){intchild=_nodes[a].cycle[direction].blossom;_nodes[child].cycle[1^direction].blossom=b;}std::swap(_nodes[a],_nodes[b]);}voidassign_surface(intblossom,intsurface,intgroup){_surface[blossom]=surface;_group[blossom]=group;if(blossom<=_vertex_count)return;for(intchild=_base[blossom];_surface[child]!=surface;child=_nodes[child].next_b()){assign_surface(child,surface,group);}}voidmerge_blossom_children(intblossom){intlargest_child=blossom;intlargest_size=1;intfirst_child=_base[blossom];for(intchild=first_child;;child=_nodes[child].next_b()){if(_nodes[child].size>largest_size){largest_size=_nodes[child].size;largest_child=child;}if(_nodes[child].next_b()==first_child)break;}for(intchild=first_child;;child=_nodes[child].next_b()){if(child!=largest_child)assign_surface(child,largest_child,child);if(_nodes[child].next_b()==first_child)break;}_group[largest_child]=largest_child;if(largest_size>1){_surface[blossom]=_heavy[blossom]=largest_child;swap_blossoms(largest_child,blossom);}else{_heavy[blossom]=0;}}voidcontract_blossom(intx,inty,intedge_id){intx_blossom=_surface[x];inty_blossom=_surface[y];assert(x_blossom!=y_blossom);constintvisit_mark=-(edge_id+1);_tree_link[_surface[_mate[x_blossom]]].from=visit_mark;_tree_link[_surface[_mate[y_blossom]]].from=visit_mark;intlca=-1;while(true){if(_mate[y_blossom]!=0)std::swap(x_blossom,y_blossom);x_blossom=lca=_surface[_tree_link[x_blossom].from];if(_tree_link[_surface[_mate[x_blossom]]].from==visit_mark)break;_tree_link[_surface[_mate[x_blossom]]].from=visit_mark;}constintblossom=_unused_blossoms[--_unused_count];assert(_unused_count>=0);inttree_size=0;for(intdirection=0;direction<2;direction++){for(intchild=_surface[x];child!=lca;){intmatched_vertex=_mate[child];intmatched_child=_surface[matched_vertex];intvertex=_mate[matched_vertex];intlink_from=_tree_link[vertex].from;intlink_to=_tree_link[vertex].to;tree_size+=_nodes[child].size+_nodes[matched_child].size;_tree_link[matched_vertex]={x,y};if(child>_vertex_count){_potential[child]+=(_time-_created_at[child])<<1;}if(matched_child>_vertex_count)_expand_heap.erase(matched_child);make_outer(matched_child,materialize_potential<inner_label>(matched_child));_nodes[child].cycle[direction]={matched_child,matched_vertex};_nodes[matched_child].cycle[1^direction]={child,vertex};child=_surface[link_from];_nodes[matched_child].cycle[direction]={child,link_from};_nodes[child].cycle[1^direction]={matched_child,link_to};}_nodes[_surface[x]].cycle[1^direction]={_surface[y],y};std::swap(x,y);}if(lca>_vertex_count)_potential[lca]+=(_time-_created_at[lca])<<1;_nodes[blossom].size=tree_size+_nodes[lca].size;_base[blossom]=lca;_tree_link[blossom]=_tree_link[lca];_mate[blossom]=_mate[lca];_label[blossom]=outer_label;_surface[blossom]=blossom;_created_at[blossom]=_time;_potential[blossom]=0;_lazy[blossom]=0;merge_blossom_children(blossom);}voidlink_blossom(intblossom,BlossomLinklink){_tree_link[blossom]=link;if(blossom<=_vertex_count)return;intfirst_child=_base[blossom];link_blossom(first_child,link);intprevious_child=_nodes[first_child].prev_b();link={_nodes[previous_child].next_v(),_nodes[first_child].prev_v()};for(intchild=first_child;;){intnext_child=_nodes[child].next_b();if(next_child==first_child)break;link_blossom(next_child,link);BlossomLinknext_link={_nodes[next_child].prev_v(),_nodes[child].next_v()};child=_nodes[next_child].next_b();link_blossom(child,next_link);}}voidmake_outer(intblossom,cost_typedelta){_label[blossom]=outer_label;if(blossom>_vertex_count){for(intchild=_base[blossom];_label[child]!=outer_label;child=_nodes[child].next_b()){make_outer(child,delta);}}else{_potential[blossom]+=_time+delta;if(_potential[blossom]<_vertex_event.time){_vertex_event={_potential[blossom],blossom};}_queue.enqueue(blossom);}}boolgrow_tree(intfrom,intto){intinner_blossom=_surface[to];boolvisited=(_label[inner_blossom]!=free_label);if(!visited)link_blossom(inner_blossom,{0,0});_label[inner_blossom]=inner_label;_created_at[inner_blossom]=_time;_grow_heap.erase(inner_blossom);if(to!=inner_blossom){_expand_heap.update(inner_blossom,_time+(_potential[inner_blossom]>>1));}intmatched_vertex=_mate[inner_blossom];if(matched_vertex==0){rematch(from,to);rematch(to,from);returntrue;}intouter_blossom=_surface[matched_vertex];if(!visited){link_blossom(outer_blossom,{from,to});}else{_tree_link[outer_blossom]=_tree_link[matched_vertex]={from,to};}make_outer(outer_blossom,materialize_potential<free_label>(outer_blossom));_created_at[outer_blossom]=_time;_grow_heap.erase(outer_blossom);returnfalse;}voidrelease_blossom(intblossom){_unused_blossoms[_unused_count++]=blossom;_base[blossom]=blossom;}intrecompute_slack(intblossom,intgroup){if(blossom<=_vertex_count){if(_slack[blossom]>=_slack[group])return0;_slack[group]=_slack[blossom];_best_from[group]=_best_from[blossom];returnblossom;}intdestination=0;intfirst_child=_base[blossom];for(intchild=first_child;;child=_nodes[child].next_b()){intcandidate=recompute_slack(child,group);if(candidate!=0)destination=candidate;if(_nodes[child].next_b()==first_child)break;}returndestination;}voidrebuild_components(intblossom,intsurface,intgroup){_surface[blossom]=surface;_group[blossom]=group;if(blossom<=_vertex_count)return;for(intchild=_base[blossom];_surface[child]!=surface;child=_nodes[child].next_b()){if(child==_heavy[blossom]){rebuild_components(child,surface,group);}else{assign_surface(child,surface,child);intdestination=0;if(child>_vertex_count){_slack[child]=infinity;destination=recompute_slack(child,child);}elseif(_slack[child]<infinity){destination=child;}if(destination>0){_blossom_grow_heaps.push(surface,child,EdgeEvent(_slack[child],_best_from[child],destination));}}}}voidpromote_largest_child(intblossom){intlargest_child=_heavy[blossom];cost_typedelta=(_time-_created_at[blossom])+_lazy[blossom];_lazy[blossom]=0;intfirst_child=_base[blossom];for(intchild=first_child;;child=_nodes[child].next_b()){_created_at[child]=_time;_lazy[child]=delta;if(child!=largest_child){rebuild_components(child,child,child);_blossom_grow_heaps.erase(blossom,child);}if(_nodes[child].next_b()==first_child)break;}if(largest_child>0){swap_blossoms(largest_child,blossom);blossom=largest_child;}release_blossom(blossom);}voidexpand_blossom(intblossom){intmatched_vertex=_mate[_base[blossom]];promote_largest_child(blossom);BlossomLinkold_link=_tree_link[matched_vertex];intold_base=_surface[_mate[matched_vertex]];introot=_surface[old_link.to];intdirection=(_mate[root]==_nodes[root].cycle[0].vertex)?1:0;for(intchild=_nodes[old_base].cycle[direction^1].blossom;child!=root;){_label[child]=separated_label;activate_grow_event(child);child=_nodes[child].cycle[direction^1].blossom;_label[child]=separated_label;activate_grow_event(child);child=_nodes[child].cycle[direction^1].blossom;}for(intchild=old_base;;child=_nodes[child].cycle[direction].blossom){_label[child]=inner_label;intnext_child=_nodes[child].cycle[direction].blossom;if(child==root){_tree_link[_mate[child]]=old_link;}else{_tree_link[_mate[child]]={_nodes[child].cycle[direction].vertex,_nodes[next_child].cycle[direction^1].vertex};}_tree_link[_surface[_mate[child]]]=_tree_link[_mate[child]];if(child>_vertex_count){if(_potential[child]==0){expand_blossom(child);}else{_expand_heap.push(child,_time+(_potential[child]>>1));}}if(child==root)break;child=next_child;make_outer(next_child,materialize_potential<inner_label>(next_child));}}boolscan_tight_edges(introot){while(!_queue.empty()){intfrom=_queue.dequeue();intfrom_blossom=_surface[from];if(_potential[from]==_time){if(from!=root)rematch(from,0);returntrue;}for(intedge_id=_offset[from];edge_id<_offset[from+1];edge_id++){constSolverEdge&edge=_edges[edge_id];intto=edge.to;intto_blossom=_surface[to];if(from_blossom==to_blossom)continue;BlossomLabelto_label=_label[to_blossom];if(to_label==outer_label){cost_typeevent_time=cost_type(reduced_cost(from,to,edge)>>1);if(event_time==_time){contract_blossom(from,to,edge_id);from_blossom=_surface[from];}elseif(event_time<_vertex_event.time){_contract_heap.emplace(event_time,from,edge_id);}}else{total_typeevent_time=reduced_cost(from,to,edge);if(event_time>=infinity)continue;if(to_label!=inner_label){if(cost_type(event_time)+_lazy[to_blossom]==_time){if(grow_tree(from,to))returntrue;}else{update_grow_event<free_label>(from,to,to_blossom,cost_type(event_time));}}elseif(_mate[from]!=to){update_grow_event<inner_label>(from,to,to_blossom,cost_type(event_time));}}}}returnfalse;}booladvance_dual(introot){cost_typerematch_time=_vertex_event.time;cost_typegrow_time=infinity;if(!_grow_heap.empty())grow_time=_grow_heap.min().time;cost_typecontract_time=infinity;while(!_contract_heap.empty()){EdgeEventevent=_contract_heap.min();intfrom=event.from;intto=_edges[event.to].to;if(_surface[from]!=_surface[to]){contract_time=event.time;break;}else{_contract_heap.pop();}}cost_typeexpand_time=infinity;if(!_expand_heap.empty())expand_time=_expand_heap.min();cost_typenext_time=std::min(std::min(rematch_time,grow_time),std::min(contract_time,expand_time));assert(_time<=next_time&&next_time<infinity);_time=next_time;if(_time==_vertex_event.time){intx=_vertex_event.id;if(x!=root)rematch(x,0);returntrue;}while(!_grow_heap.empty()&&_grow_heap.min().time==_time){intfrom=_grow_heap.min().from;intto=_grow_heap.min().to;if(grow_tree(from,to))returntrue;}while(!_contract_heap.empty()&&_contract_heap.min().time==_time){intfrom=_contract_heap.min().from;intedge_id=_contract_heap.min().to;intto=_edges[edge_id].to;_contract_heap.pop();if(_surface[from]==_surface[to])continue;contract_blossom(from,to,edge_id);}while(!_expand_heap.empty()&&_expand_heap.min()==_time){intblossom=_expand_heap.argmin();_expand_heap.pop();expand_blossom(blossom);}returnfalse;}private:voidinitialize_state(){_queue=FixedQueue<int>(_vertex_count);_mate.assign(_state_count,0);_tree_link.assign(_state_count,{0,0});_label.assign(_state_count,free_label);_base.resize(_state_count);for(intstate=1;state<_state_count;state++)_base[state]=state;_surface.resize(_state_count);for(intstate=1;state<_state_count;state++)_surface[state]=state;_potential.resize(_state_count);_nodes.resize(_state_count);for(intstate=1;state<_state_count;state++){_nodes[state]=BlossomNode(state);}_unused_blossoms.resize(_blossom_count);for(inti=0;i<_blossom_count;i++){_unused_blossoms[i]=_vertex_count+_blossom_count-i;}_unused_count=_blossom_count;reset_clock();_created_at.resize(_state_count);_slack.assign(_state_count,infinity);_best_from.assign(_state_count,0);_heavy.assign(_state_count,0);_lazy.assign(_state_count,0);_group.resize(_state_count);for(intstate=0;state<_state_count;state++)_group[state]=state;}voidinitialize_potentials(){for(intvertex=1;vertex<=_vertex_count;vertex++){cost_typemaximum_cost=0;for(intedge_id=_offset[vertex];edge_id<_offset[vertex+1];edge_id++){maximum_cost=std::max(maximum_cost,_edges[edge_id].cost);}_potential[vertex]=maximum_cost>>1;}}constint_vertex_count;constint_blossom_count;constint_state_count;std::vector<int>_offset;std::vector<SolverEdge>_edges;FixedQueue<int>_queue;std::vector<int>_mate;std::vector<int>_surface;std::vector<int>_base;std::vector<BlossomLink>_tree_link;std::vector<BlossomLabel>_label;std::vector<cost_type>_potential;std::vector<int>_unused_blossoms;int_unused_count;std::vector<BlossomNode>_nodes;// Heavy children and event queues keep each search phase at O(m log n).std::vector<int>_heavy;std::vector<int>_group;std::vector<cost_type>_created_at;std::vector<cost_type>_lazy;std::vector<cost_type>_slack;std::vector<int>_best_from;cost_type_time;VertexEvent_vertex_event;MutableBinaryHeap<EdgeEvent>_grow_heap;DisjointPairingHeaps<EdgeEvent>_blossom_grow_heaps;ReservablePriorityQueue<EdgeEvent>_contract_heap;MutableBinaryHeap<cost_type>_expand_heap;};}// namespace internaltemplate<classCost,classTotalCost=Cost>structGeneralWeightedMatching{static_assert(std::is_integral_v<Cost>&&std::is_signed_v<Cost>);static_assert(std::is_integral_v<TotalCost>&&std::is_signed_v<TotalCost>);structEdge{intfrom;intto;Costcost;intid;boolalive;intother(intvertex)const{assert(vertex==from||vertex==to);returnfrom^to^vertex;}};structPair{intfrom;intto;Costcost;intedge_id;};private:int_n;std::vector<Edge>_edges;std::vector<std::vector<int>>_adj;std::vector<int>_mate;std::vector<int>_mate_edge;TotalCost_matching_weight;bool_calculated;voidinvalidate(){_calculated=false;}voidensure_matching(){if(!_calculated)max_weight_matching();}public:GeneralWeightedMatching():GeneralWeightedMatching(0){}explicitGeneralWeightedMatching(intn):_n(n),_adj(n),_mate(n,-1),_mate_edge(n,-1),_matching_weight(),_calculated(false){assert(0<=n);}intsize()const{return_n;}intedge_count()const{returnint(_edges.size());}intadd_edge(intfrom,intto,Costcost){assert(0<=from&&from<_n);assert(0<=to&&to<_n);assert(from!=to);assert(cost<=std::numeric_limits<Cost>::max()/Cost(2));intid=int(_edges.size());_edges.push_back(Edge{from,to,cost,id,true});_adj[from].push_back(id);_adj[to].push_back(id);invalidate();returnid;}Edgeget_edge(intid)const{assert(0<=id&&id<int(_edges.size()));return_edges[id];}std::vector<Edge>edges(boolinclude_inactive=false)const{std::vector<Edge>result;result.reserve(_edges.size());for(constEdge&edge:_edges){if(include_inactive||edge.alive)result.push_back(edge);}returnresult;}voidset_edge_alive(intid,boolalive){assert(0<=id&&id<int(_edges.size()));_edges[id].alive=alive;invalidate();}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<int(_edges.size()));return_edges[id].alive;}TotalCostmax_weight_matching(){usingSolver=internal::WeightedBlossomSolver<Cost,TotalCost>;std::vector<typenameSolver::InputEdge>input;input.reserve(_edges.size());for(constEdge&edge:_edges){if(!edge.alive||edge.cost<=Cost())continue;input.push_back(typenameSolver::InputEdge{edge.from+1,edge.to+1,edge.cost});}Solversolver(_n,input);std::vector<std::pair<int,int>>vertex_pairs;solver.solve(vertex_pairs);_mate.assign(_n,-1);_mate_edge.assign(_n,-1);_matching_weight=TotalCost();for(auto[one_based_from,one_based_to]:vertex_pairs){intfrom=one_based_from-1;intto=one_based_to-1;intbest_edge=-1;for(intid:_adj[from]){constEdge&edge=_edges[id];if(!edge.alive||edge.other(from)!=to||edge.cost<=Cost())continue;if(best_edge==-1||_edges[best_edge].cost<edge.cost)best_edge=id;}assert(best_edge!=-1);_mate[from]=to;_mate[to]=from;_mate_edge[from]=best_edge;_mate_edge[to]=best_edge;_matching_weight+=static_cast<TotalCost>(_edges[best_edge].cost);}_calculated=true;return_matching_weight;}TotalCostmatching_weight(){ensure_matching();return_matching_weight;}intmatching_size(){ensure_matching();intresult=0;for(intvertex=0;vertex<_n;vertex++){if(vertex<_mate[vertex])result++;}returnresult;}std::vector<int>mate(){ensure_matching();return_mate;}std::vector<int>mate_edge(){ensure_matching();return_mate_edge;}std::vector<Pair>matching(){ensure_matching();std::vector<Pair>result;for(intvertex=0;vertex<_n;vertex++){if(vertex<_mate[vertex]){intid=_mate_edge[vertex];result.push_back(Pair{vertex,_mate[vertex],_edges[id].cost,id});}}returnresult;}};template<classCost,classTotalCost=Cost>structGeneralWeightedMatchingGraph{GeneralWeightedMatching<Cost,TotalCost>matching;std::vector<int>original_edge_id;intoriginal_edge(intedge_id)const{assert(0<=edge_id&&edge_id<int(original_edge_id.size()));returnoriginal_edge_id[edge_id];}};template<classT>GeneralWeightedMatchingGraph<T>make_general_weighted_matching(constGraph<T>&graph){GeneralWeightedMatchingGraph<T>result;result.matching=GeneralWeightedMatching<T>(graph.size());for(constauto&edge:graph.edges()){intid=result.matching.add_edge(edge.from,edge.to,edge.cost);if(int(result.original_edge_id.size())<=id){result.original_edge_id.resize(id+1);}result.original_edge_id[id]=edge.id;}returnresult;}}// namespace graph}// namespace m1une#line 4 "verify/graph/general_weighted_matching.test.cpp"
#line 7 "verify/graph/general_weighted_matching.test.cpp"
#include<cstdint>
#line 1 "utilities/fast_io.hpp"
#line 6 "utilities/fast_io.hpp"
#include<cerrno>
#include<charconv>
#line 9 "utilities/fast_io.hpp"
#include<cstdio>
#include<cstdlib>
#line 12 "utilities/fast_io.hpp"
#include<cstring>
#include<iterator>
#include<string>
#include<sys/stat.h>
#line 18 "utilities/fast_io.hpp"
#include<unistd.h>
#line 20 "utilities/fast_io.hpp"
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 11 "verify/graph/general_weighted_matching.test.cpp"
namespace{usingMatching=m1une::graph::GeneralWeightedMatching<int,longlong>;longlongnaive(constMatching&graph){intn=graph.size();std::vector<longlong>dp(1<<n,std::numeric_limits<longlong>::min());dp[0]=0;for(intmask=0;mask<(1<<n);mask++){if(dp[mask]==std::numeric_limits<longlong>::min())continue;intfrom=0;while(from<n&&(mask>>from&1))from++;if(from==n)continue;dp[mask|(1<<from)]=std::max(dp[mask|(1<<from)],dp[mask]);for(constauto&edge:graph.edges()){if(edge.cost<=0)continue;intto=-1;if(edge.from==from)to=edge.to;if(edge.to==from)to=edge.from;if(to==-1||(mask>>to&1))continue;intnext=mask|(1<<from)|(1<<to);dp[next]=std::max(dp[next],dp[mask]+edge.cost);}}return*std::max_element(dp.begin(),dp.end());}voidvalidate(Matching&graph){longlongexpected=naive(graph);assert(graph.max_weight_matching()==expected);assert(graph.matching_weight()==expected);std::vector<char>used(graph.size(),false);longlongactual=0;for(constauto&pair:graph.matching()){assert(!used[pair.from]&&!used[pair.to]);used[pair.from]=used[pair.to]=true;autoedge=graph.get_edge(pair.edge_id);assert(edge.alive);assert(edge.cost==pair.cost);assert((edge.from==pair.from&&edge.to==pair.to)||(edge.from==pair.to&&edge.to==pair.from));actual+=pair.cost;}assert(actual==expected);automate=graph.mate();automate_edge=graph.mate_edge();for(intvertex=0;vertex<graph.size();vertex++){if(mate[vertex]==-1){assert(mate_edge[vertex]==-1);}else{assert(mate[mate[vertex]]==vertex);assert(mate_edge[mate[vertex]]==mate_edge[vertex]);}}}voidtest_fixed(){Matchingempty;validate(empty);Matchinggraph(6);intedge_01=graph.add_edge(0,1,8);graph.add_edge(1,2,9);graph.add_edge(2,0,10);graph.add_edge(2,3,7);graph.add_edge(3,4,6);graph.add_edge(4,5,5);graph.add_edge(5,3,4);graph.add_edge(0,1,11);graph.add_edge(0,5,-100);validate(graph);graph.erase_edge(edge_01);assert(!graph.is_edge_alive(edge_01));validate(graph);graph.revive_edge(edge_01);validate(graph);m1une::graph::Graph<int>source(3);intoriginal_01=source.add_edge(0,1,4);source.add_edge(1,2,7);intinactive=source.add_edge(0,2,100);source.erase_edge(inactive);autobuilt=m1une::graph::make_general_weighted_matching(source);assert(built.matching.edge_count()==2);assert(built.matching.max_weight_matching()==7);assert(built.original_edge(0)==original_01);}voidtest_randomized(){std::uint64_tstate=123456789;autorandom=[&](){state^=state<<7;state^=state>>9;returnstate;};for(inttrial=0;trial<1000;trial++){intn=int(random()%10);Matchinggraph(n);intedge_count=int(random()%35);for(inti=0;i<edge_count&&n>=2;i++){intfrom=int(random()%n);intto=int(random()%n);if(from==to)continue;intcost=int(random()%31)-10;intid=graph.add_edge(from,to,cost);if(random()%7==0)graph.erase_edge(id);}validate(graph);}}}// namespaceintmain(){m1une::utilities::FastInputfast_input;m1une::utilities::FastOutputfast_output;test_fixed();test_randomized();intn,edge_count;fast_input>>n>>edge_count;Matchinggraph(n);while(edge_count--){intfrom,to,cost;fast_input>>from>>to>>cost;graph.add_edge(from,to,cost);}longlongweight=graph.max_weight_matching();automatching=graph.matching();fast_output<<matching.size()<<' '<<weight<<'\n';for(constauto&pair:matching){fast_output<<pair.from<<' '<<pair.to<<'\n';}}