#pragma once
#include"../graph/biconnected-components.hpp"// aux : block cut tree// id(V) : new id of node V// is_arti(V) : return if V is articulationtemplate<typenameG>structBlockCutTree{constG&g;BiConnectedComponents<G>bcc;vector<vector<int>>aux;vector<int>idar,idcc;BlockCutTree(constG&_g):g(_g),bcc(g){build();}voidbuild(){autoar=bcc.articulation;idar.resize(g.size(),-1);idcc.resize(g.size(),-1);for(inti=0;i<(int)ar.size();i++)idar[ar[i]]=i;aux.resize(ar.size()+bcc.bc.size());vector<int>last(g.size(),-1);for(inti=0;i<(int)bcc.bc.size();i++){vector<int>st;for(auto&[u,v]:bcc.bc[i])st.push_back(u),st.push_back(v);for(auto&u:st){if(idar[u]==-1)idcc[u]=i+ar.size();elseif(last[u]!=i){add(i+ar.size(),idar[u]);last[u]=i;}}}}vector<int>&operator[](inti){returnaux[i];}intsize()const{returnaux.size();}intid(inti){returnidar[i]==-1?idcc[i]:idar[i];}boolis_arti(inti){returnidar[i]!=-1;}intarti()const{returnbcc.articulation.size();}private:voidadd(inti,intj){if(i==-1orj==-1)return;aux[i].push_back(j);aux[j].push_back(i);};};/**
* @brief Block Cut Tree
*/
#line 2 "tree/block-cut-tree.hpp"
#line 2 "graph/biconnected-components.hpp"
#line 2 "graph/lowlink.hpp"
#include<vector>usingnamespacestd;#line 2 "graph/graph-template.hpp"
template<typenameT>structedge{intsrc,to;Tcost;edge(int_to,T_cost):src(-1),to(_to),cost(_cost){}edge(int_src,int_to,T_cost):src(_src),to(_to),cost(_cost){}edge&operator=(constint&x){to=x;return*this;}operatorint()const{returnto;}};template<typenameT>usingEdges=vector<edge<T>>;template<typenameT>usingWeightedGraph=vector<Edges<T>>;usingUnweightedGraph=vector<vector<int>>;// Input of (Unweighted) GraphUnweightedGraphgraph(intN,intM=-1,boolis_directed=false,boolis_1origin=true){UnweightedGraphg(N);if(M==-1)M=N-1;for(int_=0;_<M;_++){intx,y;cin>>x>>y;if(is_1origin)x--,y--;g[x].push_back(y);if(!is_directed)g[y].push_back(x);}returng;}// Input of Weighted Graphtemplate<typenameT>WeightedGraph<T>wgraph(intN,intM=-1,boolis_directed=false,boolis_1origin=true){WeightedGraph<T>g(N);if(M==-1)M=N-1;for(int_=0;_<M;_++){intx,y;cin>>x>>y;Tc;cin>>c;if(is_1origin)x--,y--;g[x].emplace_back(x,y,c);if(!is_directed)g[y].emplace_back(y,x,c);}returng;}// Input of Edgestemplate<typenameT>Edges<T>esgraph([[maybe_unused]]intN,intM,intis_weighted=true,boolis_1origin=true){Edges<T>es;for(int_=0;_<M;_++){intx,y;cin>>x>>y;Tc;if(is_weighted)cin>>c;elsec=1;if(is_1origin)x--,y--;es.emplace_back(x,y,c);}returnes;}// Input of Adjacency Matrixtemplate<typenameT>vector<vector<T>>adjgraph(intN,intM,TINF,intis_weighted=true,boolis_directed=false,boolis_1origin=true){vector<vector<T>>d(N,vector<T>(N,INF));for(int_=0;_<M;_++){intx,y;cin>>x>>y;Tc;if(is_weighted)cin>>c;elsec=1;if(is_1origin)x--,y--;d[x][y]=c;if(!is_directed)d[y][x]=c;}returnd;}/**
* @brief グラフテンプレート
* @docs docs/graph/graph-template.md
*/#line 7 "graph/lowlink.hpp"
// bridge ... 橋 (辺 (u, v) が u < v となるように格納)// articulation point ... 関節点template<typenameG>structLowLink{constG&g;intN;vector<int>ord,low,articulation;vector<pair<int,int>>bridge;LowLink(constG&_g):g(_g),N(g.size()),ord(N,-1),low(N,-1){for(inti=0,k=0;i<N;i++){if(ord[i]==-1){k=dfs(i,k,-1);}}}intdfs(intidx,intk,intpar){low[idx]=(ord[idx]=k++);intcnt=0;boolarti=false,second=false;for(auto&to:g[idx]){if(ord[to]==-1){cnt++;k=dfs(to,k,idx);low[idx]=min(low[idx],low[to]);arti|=(par!=-1)&&(low[to]>=ord[idx]);if(ord[idx]<low[to]){bridge.emplace_back(minmax(idx,(int)to));}}elseif(to!=par||second){low[idx]=min(low[idx],ord[to]);}else{second=true;}}arti|=par==-1&&cnt>1;if(arti)articulation.push_back(idx);returnk;}};#line 4 "graph/biconnected-components.hpp"
template<typenameG>structBiConnectedComponents:LowLink<G>{usingLL=LowLink<G>;vector<int>used;vector<vector<pair<int,int>>>bc;vector<pair<int,int>>tmp;BiConnectedComponents(constG&_g):LL(_g){build();}voidbuild(){used.assign(this->g.size(),0);for(inti=0;i<(int)used.size();i++){if(!used[i])dfs(i,-1);}}voiddfs(intidx,intpar){used[idx]=true;for(auto&to:this->g[idx]){if(to==par)continue;if(!used[to]||this->ord[to]<this->ord[idx]){tmp.emplace_back(minmax<int>(idx,to));}if(!used[to]){dfs(to,idx);if(this->low[to]>=this->ord[idx]){bc.emplace_back();while(true){autoe=tmp.back();bc.back().emplace_back(e);tmp.pop_back();if(e.first==min<int>(idx,to)&&e.second==max<int>(idx,to)){break;}}}}}}};/**
* @brief 二重頂点連結分解
*/#line 4 "tree/block-cut-tree.hpp"
// aux : block cut tree// id(V) : new id of node V// is_arti(V) : return if V is articulationtemplate<typenameG>structBlockCutTree{constG&g;BiConnectedComponents<G>bcc;vector<vector<int>>aux;vector<int>idar,idcc;BlockCutTree(constG&_g):g(_g),bcc(g){build();}voidbuild(){autoar=bcc.articulation;idar.resize(g.size(),-1);idcc.resize(g.size(),-1);for(inti=0;i<(int)ar.size();i++)idar[ar[i]]=i;aux.resize(ar.size()+bcc.bc.size());vector<int>last(g.size(),-1);for(inti=0;i<(int)bcc.bc.size();i++){vector<int>st;for(auto&[u,v]:bcc.bc[i])st.push_back(u),st.push_back(v);for(auto&u:st){if(idar[u]==-1)idcc[u]=i+ar.size();elseif(last[u]!=i){add(i+ar.size(),idar[u]);last[u]=i;}}}}vector<int>&operator[](inti){returnaux[i];}intsize()const{returnaux.size();}intid(inti){returnidar[i]==-1?idcc[i]:idar[i];}boolis_arti(inti){returnidar[i]!=-1;}intarti()const{returnbcc.articulation.size();}private:voidadd(inti,intj){if(i==-1orj==-1)return;aux[i].push_back(j);aux[j].push_back(i);};};/**
* @brief Block Cut Tree
*/