#pragma once
#include"template.hpp"/**
* Description: General weighted matching using blossom algorithm.
* Time: O(|V|^3) \text{(fast in practice)}
*/template<intN,classT>structGeneralWeightedMatching{staticconstTINF=numeric_limits<T>::max();structEdge{intu,v;Tw;Edge(){}Edge(intu,intv,Tw):u(u),v(v),w(w){}};intn,n_x;Edgeg[N*2][N*2];Tlab[N*2];intmatch[N*2],slack[N*2],st[N*2],pa[N*2];intflo_from[N*2][N+1],S[N*2],vis[N*2];vector<int>flo[N*2];queue<int>q;Te_delta(constEdge&e){returnlab[e.u]+lab[e.v]-g[e.u][e.v].w*2;}voidupdate_slack(intu,intx){if(!slack[x]||e_delta(g[u][x])<e_delta(g[slack[x]][x]))slack[x]=u;}voidset_slack(intx){slack[x]=0;for(intu=1;u<=n;u++)if(g[u][x].w>0&&st[u]!=x&&S[st[u]]==0)update_slack(u,x);}voidq_push(intx){if(x<=n)q.push(x);elsefor(autoxs:flo[x])q_push(xs);}voidset_st(intx,intb){st[x]=b;if(x>n)for(autoxs:flo[x])set_st(xs,b);}intget_pr(intb,intxr){intpr=find(ALL(flo[b]),xr)-flo[b].begin();if(pr&1){reverse(1+ALL(flo[b]));returnSZ(flo[b])-pr;}returnpr;}voidset_match(intu,intv){Edgee=g[u][v];match[u]=g[u][v].v;if(u<=n)return;intxr=flo_from[u][e.u],pr=get_pr(u,xr);for(inti=0;i<pr;i++)set_match(flo[u][i],flo[u][i^1]);set_match(xr,v);rotate(flo[u].begin(),pr+ALL(flo[u]));}voidaugment(intu,intv){while(true){intxnv=st[match[u]];set_match(u,v);if(!xnv)return;set_match(xnv,st[pa[xnv]]);u=st[pa[xnv]];v=xnv;}}intget_lca(intu,intv){staticintt=0;for(++t;u||v;swap(u,v)){if(u==0)continue;if(vis[u]==t)returnu;vis[u]=t;u=st[match[u]];if(u)u=st[pa[u]];}return0;}voidadd_blossom(intu,intlca,intv){intb=n+1;while(b<=n_x&&st[b])++b;if(b>n_x)++n_x;//new blossom;lab[b]=0;S[b]=0;match[b]=match[lca];flo[b]=vector<int>{lca};for(intx=u,y;x!=lca;x=st[pa[y]])flo[b].eb(x),flo[b].eb(y=st[match[x]]),q_push(y);reverse(1+ALL(flo[b]));for(intx=v,y;x!=lca;x=st[pa[y]])flo[b].eb(x),flo[b].eb(y=st[match[x]]),q_push(y);set_st(b,b);for(intx=1;x<=n_x;x++)g[b][x].w=g[x][b].w=0;for(intx=1;x<=n;x++)flo_from[b][x]=0;for(autoxs:flo[b]){for(intx=1;x<=n_x;x++)if(g[b][x].w==0||e_delta(g[xs][x])<e_delta(g[b][x]))g[b][x]=g[xs][x],g[x][b]=g[x][xs];for(intx=1;x<=n;x++)if(flo_from[xs][x])flo_from[b][x]=xs;}set_slack(b);}voidexpand_blossom(intb){for(autoxs:flo[b])set_st(xs,xs);intxr=flo_from[b][g[b][pa[b]].u],pr=get_pr(b,xr);for(inti=0;i<pr;i+=2){intxs=flo[b][i],xns=flo[b][i+1];pa[xs]=g[xns][xs].u;S[xs]=1;S[xns]=0;slack[xs]=0,set_slack(xns);q_push(xns);}S[xr]=1,pa[xr]=pa[b];for(inti=pr+1;i<SZ(flo[b]);i++)S[flo[b][i]]=-1,set_slack(flo[b][i]);st[b]=0;}boolon_found_edge(constEdge&e){intu=st[e.u],v=st[e.v];if(S[v]==-1){pa[v]=e.u;S[v]=1;intnu=st[match[v]];slack[v]=slack[nu]=S[nu]=0;q_push(nu);}elseif(S[v]==0){intlca=get_lca(u,v);if(!lca)returnaugment(u,v),augment(v,u),true;add_blossom(u,lca,v);}returnfalse;}boolmatching(){for(inti=1;i<=n_x;i++)S[i]=-1;for(inti=1;i<=n_x;i++)slack[i]=-0;q=queue<int>();for(intx=1;x<=n_x;x++)if(st[x]==x&&!match[x])pa[x]=S[x]=0,q_push(x);if(q.empty())returnfalse;while(true){while(!q.empty()){intu=q.front();q.pop();if(S[st[u]]==1)continue;for(intv=1;v<=n;v++)if(g[u][v].w>0&&st[u]!=st[v]){if(e_delta(g[u][v])==0){if(on_found_edge(g[u][v]))returntrue;}elseupdate_slack(u,st[v]);}}Td=INF;for(intb=n+1;b<=n_x;b++)if(st[b]==b&&S[b]==1)d=min(d,lab[b]/2);for(intx=1;x<=n_x;x++)if(st[x]==x&&slack[x]){if(S[x]==-1)d=min(d,e_delta(g[slack[x]][x]));elseif(S[x]==0)d=min(d,e_delta(g[slack[x]][x])/2);}for(intu=1;u<=n;u++){if(S[st[u]]==0){if(lab[u]<=d)return0;lab[u]-=d;}elseif(S[st[u]]==1)lab[u]+=d;}for(intb=n+1;b<=n_x;b++)if(st[b]==b){if(S[st[b]]==0)lab[b]+=d*2;elseif(S[st[b]]==1)lab[b]-=d*2;}q=queue<int>();for(intx=1;x<=n_x;x++)if(st[x]==x&&slack[x]&&st[slack[x]]!=x&&e_delta(g[slack[x]][x])==0)if(on_found_edge(g[slack[x]][x]))returntrue;for(intb=n+1;b<=n_x;b++)if(st[b]==b&&S[b]==1&&lab[b]==0)expand_blossom(b);}returnfalse;}pair<T,int>solve(){for(inti=1;i<=n;i++)match[i]=0;n_x=n;intn_matches=0;Tw_max=0,tot_weight=0;for(intu=0;u<=n;u++)st[u]=u,flo[u].clear();for(intu=1;u<=n;u++)for(intv=1;v<=n;v++)flo_from[u][v]=u==v?u:0,w_max=max(w_max,g[u][v].w);for(intu=1;u<=n;u++)lab[u]=w_max;while(matching())++n_matches;for(intu=1;u<=n;u++)if(match[u]&&match[u]<u)tot_weight+=g[u][match[u]].w;returnmake_pair(tot_weight,n_matches);}voidadd_edge(intu,intv,Tw){if(w<=g[u][v].w)return;g[u][v].w=g[v][u].w=w;}voidinit(int_n){n=_n;for(intu=1;u<=n;u++)for(intv=1;v<=n;v++)g[u][v]=Edge(u,v,T(0));}};