/** 一般图最大匹配(Graph 带花树算法)【久远】
* 2021-12-24: https://codeforces.com/contest/1615/submission/140509278
**/structGraph{intn;std::vector<std::vector<int>>e;Graph(intn):n(n),e(n){}voidaddEdge(intu,intv){e[u].push_back(v);e[v].push_back(u);}std::vector<int>findMatching(){std::vector<int>match(n,-1),vis(n),link(n),f(n),dep(n);// disjoint set union
autofind=[&](intu){while(f[u]!=u)u=f[u]=f[f[u]];returnu;};autolca=[&](intu,intv){u=find(u);v=find(v);while(u!=v){if(dep[u]<dep[v])std::swap(u,v);u=find(link[match[u]]);}returnu;};std::queue<int>que;autoblossom=[&](intu,intv,intp){while(find(u)!=p){link[u]=v;v=match[u];if(vis[v]==0){vis[v]=1;que.push(v);}f[u]=f[v]=p;u=link[v];}};// find an augmenting path starting from u and augment (if exist)
autoaugment=[&](intu){while(!que.empty())que.pop();std::iota(f.begin(),f.end(),0);// vis = 0 corresponds to inner vertices, vis = 1 corresponds to outer vertices
std::fill(vis.begin(),vis.end(),-1);que.push(u);vis[u]=1;dep[u]=0;while(!que.empty()){intu=que.front();que.pop();for(autov:e[u]){if(vis[v]==-1){vis[v]=0;link[v]=u;dep[v]=dep[u]+1;// found an augmenting path
if(match[v]==-1){for(intx=v,y=u,temp;y!=-1;x=temp,y=x==-1?-1:link[x]){temp=match[y];match[x]=y;match[y]=x;}return;}vis[match[v]]=1;dep[match[v]]=dep[u]+2;que.push(match[v]);}elseif(vis[v]==1&&find(v)!=find(u)){// found a blossom
intp=lca(u,v);blossom(u,v,p);blossom(v,u,p);}}}};// find a maximal matching greedily (decrease constant)
autogreedy=[&](){for(intu=0;u<n;++u){if(match[u]!=-1)continue;for(autov:e[u]){if(match[v]==-1){match[u]=v;match[v]=u;break;}}}};greedy();for(intu=0;u<n;++u)if(match[u]==-1)augment(u);returnmatch;}};
#line 1 "src/jiangly/graph/04-Graph-Match.hpp"
/** 一般图最大匹配(Graph 带花树算法)【久远】
* 2021-12-24: https://codeforces.com/contest/1615/submission/140509278
**/structGraph{intn;std::vector<std::vector<int>>e;Graph(intn):n(n),e(n){}voidaddEdge(intu,intv){e[u].push_back(v);e[v].push_back(u);}std::vector<int>findMatching(){std::vector<int>match(n,-1),vis(n),link(n),f(n),dep(n);// disjoint set union
autofind=[&](intu){while(f[u]!=u)u=f[u]=f[f[u]];returnu;};autolca=[&](intu,intv){u=find(u);v=find(v);while(u!=v){if(dep[u]<dep[v])std::swap(u,v);u=find(link[match[u]]);}returnu;};std::queue<int>que;autoblossom=[&](intu,intv,intp){while(find(u)!=p){link[u]=v;v=match[u];if(vis[v]==0){vis[v]=1;que.push(v);}f[u]=f[v]=p;u=link[v];}};// find an augmenting path starting from u and augment (if exist)
autoaugment=[&](intu){while(!que.empty())que.pop();std::iota(f.begin(),f.end(),0);// vis = 0 corresponds to inner vertices, vis = 1 corresponds to outer vertices
std::fill(vis.begin(),vis.end(),-1);que.push(u);vis[u]=1;dep[u]=0;while(!que.empty()){intu=que.front();que.pop();for(autov:e[u]){if(vis[v]==-1){vis[v]=0;link[v]=u;dep[v]=dep[u]+1;// found an augmenting path
if(match[v]==-1){for(intx=v,y=u,temp;y!=-1;x=temp,y=x==-1?-1:link[x]){temp=match[y];match[x]=y;match[y]=x;}return;}vis[match[v]]=1;dep[match[v]]=dep[u]+2;que.push(match[v]);}elseif(vis[v]==1&&find(v)!=find(u)){// found a blossom
intp=lca(u,v);blossom(u,v,p);blossom(v,u,p);}}}};// find a maximal matching greedily (decrease constant)
autogreedy=[&](){for(intu=0;u<n;++u){if(match[u]!=-1)continue;for(autov:e[u]){if(match[v]==-1){match[u]=v;match[v]=u;break;}}}};greedy();for(intu=0;u<n;++u)if(match[u]==-1)augment(u);returnmatch;}};