#pragma once
#include<cassert>
#include<utility>
#include<vector>usingnamespacestd;#include"convert-tree.hpp"
#include"heavy-light-decomposition.hpp"namespaceStaticTopTreeVertexBasedImpl{enumType{Vertex,Compress,Rake,Add_Edge,Add_Vertex};template<typenameG>structStaticTopTreeVertexBased{constHeavyLightDecomposition<G>&hld;vector<vector<int>>g;introot;// 元の木の rootinttt_root;// top tree の rootvector<int>P,L,R;vector<Type>T;StaticTopTreeVertexBased(constHeavyLightDecomposition<G>&_hld):hld(_hld){root=hld.root;g=rooted_tree(hld.g,root);intn=g.size();P.resize(n,-1),L.resize(n,-1),R.resize(n,-1);T.resize(n,Type::Vertex);build();}private:intadd(intl,intr,Typet){if(t==Type::Compressort==Type::Rake){assert(l!=-1andr!=-1);}if(t==Type::Add_Edge){assert(l!=-1andr==-1);}assert(t!=Type::Vertexandt!=Type::Add_Vertex);intk=P.size();P.push_back(-1),L.push_back(l),R.push_back(r),T.push_back(t);if(l!=-1)P[l]=k;if(r!=-1)P[r]=k;returnk;}intadd2(intk,intl,intr,Typet){assert(k<(int)g.size());assert(t==Type::Vertexort==Type::Add_Vertex);if(t==Type::Vertex){assert(l==-1andr==-1);}else{assert(l!=-1andr==-1);}P[k]=-1,L[k]=l,R[k]=r,T[k]=t;if(l!=-1)P[l]=k;if(r!=-1)P[r]=k;returnk;}pair<int,int>merge(constvector<pair<int,int>>&a,Typet){assert(!a.empty());if(a.size()==1)returna[0];intsum_s=0;for(auto&[_,s]:a)sum_s+=s;vector<pair<int,int>>b,c;for(auto&[i,s]:a){(sum_s>s?b:c).emplace_back(i,s);sum_s-=s*2;}auto[i,si]=merge(b,t);auto[j,sj]=merge(c,t);return{add(i,j,t),si+sj};}pair<int,int>compress(inti){vector<pair<int,int>>chs;while(true){chs.push_back(add_vertex(i));if(g[i].empty())break;i=g[i][0];}returnmerge(chs,Type::Compress);}pair<int,int>rake(inti){vector<pair<int,int>>chs;for(intj=1;j<(int)g[i].size();j++)chs.push_back(add_edge(g[i][j]));if(chs.empty())return{-1,0};returnmerge(chs,Type::Rake);}pair<int,int>add_edge(inti){auto[j,sj]=compress(i);return{add(j,-1,Type::Add_Edge),sj};}pair<int,int>add_vertex(inti){auto[j,sj]=rake(i);return{add2(i,j,-1,j==-1?Type::Vertex:Type::Add_Vertex),sj+1};}voidbuild(){auto[i,n]=compress(root);assert((int)g.size()==n);tt_root=i;}};template<typenameG,typenamePath,typenamePoint,typenameVertex,typenameCompress,typenameRake,typenameAdd_edge,typenameAdd_vertex>structDPonStaticTopTreeVertexBased{constStaticTopTreeVertexBased<G>tt;vector<Path>path;vector<Point>point;constVertexvertex;constCompresscompress;constRakerake;constAdd_edgeadd_edge;constAdd_vertexadd_vertex;DPonStaticTopTreeVertexBased(constHeavyLightDecomposition<G>&hld,constVertex&_vertex,constCompress&_compress,constRake&_rake,constAdd_edge&_add_edge,constAdd_vertex&_add_vertex):tt(hld),vertex(_vertex),compress(_compress),rake(_rake),add_edge(_add_edge),add_vertex(_add_vertex){intn=tt.P.size();path.resize(n),point.resize(n);dfs(tt.tt_root);}Pathget(){returnpath[tt.tt_root];}voidupdate(intk){while(k!=-1)_update(k),k=tt.P[k];}private:void_update(intk){if(tt.T[k]==Type::Vertex){path[k]=vertex(k);}elseif(tt.T[k]==Type::Compress){path[k]=compress(path[tt.L[k]],path[tt.R[k]]);}elseif(tt.T[k]==Type::Rake){point[k]=rake(point[tt.L[k]],point[tt.R[k]]);}elseif(tt.T[k]==Type::Add_Edge){point[k]=add_edge(path[tt.L[k]]);}else{path[k]=add_vertex(point[tt.L[k]],k);}}voiddfs(intk){if(tt.L[k]!=-1)dfs(tt.L[k]);if(tt.R[k]!=-1)dfs(tt.R[k]);_update(k);}};}// namespace StaticTopTreeVertexBasedImplusingStaticTopTreeVertexBasedImpl::DPonStaticTopTreeVertexBased;usingStaticTopTreeVertexBasedImpl::StaticTopTreeVertexBased;/*
// template
using Path = ;
using Point = ;
auto vertex = [&](int i) -> Path {
};
auto compress = [&](const Path& p, const Path& c) -> Path {
};
auto rake = [&](const Point& a, const Point& b) -> Point {
};
auto add_edge = [&](const Path& a) -> Point {
};
auto add_vertex = [&](const Point& a, int i) -> Path {
};
HeavyLightDecomposition hld{g};
DPonStaticTopTreeVertexBased<vector<vector<int>>, Path, Point,
decltype(vertex), decltype(compress), decltype(rake), decltype(add_edge),
decltype(add_vertex)>
dp(hld, vertex, compress, rake, add_edge, add_vertex);
*//**
* @brief Static Top Tree
*/
#line 2 "tree/static-top-tree-vertex-based.hpp"
#include<cassert>
#include<utility>
#include<vector>usingnamespacestd;#line 2 "tree/convert-tree.hpp"
#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 4 "tree/convert-tree.hpp"
template<typenameT>structhas_cost{private:template<typenameU>staticautoconfirm(Uu)->decltype(u.cost,std::true_type());staticautoconfirm(...)->std::false_type;public:enum:bool{value=decltype(confirm(std::declval<T>()))::value};};template<typenameT>vector<vector<T>>inverse_tree(constvector<vector<T>>&g){intN=(int)g.size();vector<vector<T>>rg(N);for(inti=0;i<N;i++){for(auto&e:g[i]){ifconstexpr(is_same<T,int>::value){rg[e].push_back(i);}elseifconstexpr(has_cost<T>::value){rg[e].emplace_back(e.to,i,e.cost);}else{assert(0);}}}returnrg;}template<typenameT>vector<vector<T>>rooted_tree(constvector<vector<T>>&g,introot=0){intN=(int)g.size();vector<vector<T>>rg(N);vector<char>v(N,false);v[root]=true;queue<int>que;que.emplace(root);while(!que.empty()){autop=que.front();que.pop();for(auto&e:g[p]){if(v[e]==false){v[e]=true;que.push(e);rg[p].push_back(e);}}}returnrg;}/**
* @brief 根付き木・逆辺からなる木への変換
*/#line 2 "tree/heavy-light-decomposition.hpp"
#line 4 "tree/heavy-light-decomposition.hpp"
template<typenameG>structHeavyLightDecomposition{private:voiddfs_sz(intcur){size[cur]=1;for(auto&dst:g[cur]){if(dst==par[cur]){if(g[cur].size()>=2&&int(dst)==int(g[cur][0]))swap(g[cur][0],g[cur][1]);elsecontinue;}depth[dst]=depth[cur]+1;par[dst]=cur;dfs_sz(dst);size[cur]+=size[dst];if(size[dst]>size[g[cur][0]]){swap(dst,g[cur][0]);}}}voiddfs_hld(intcur){down[cur]=id++;for(autodst:g[cur]){if(dst==par[cur])continue;nxt[dst]=(int(dst)==int(g[cur][0])?nxt[cur]:int(dst));dfs_hld(dst);}up[cur]=id;}// [u, v)vector<pair<int,int>>ascend(intu,intv)const{vector<pair<int,int>>res;while(nxt[u]!=nxt[v]){res.emplace_back(down[u],down[nxt[u]]);u=par[nxt[u]];}if(u!=v)res.emplace_back(down[u],down[v]+1);returnres;}// (u, v]vector<pair<int,int>>descend(intu,intv)const{if(u==v)return{};if(nxt[u]==nxt[v])return{{down[u]+1,down[v]}};autores=descend(u,par[nxt[v]]);res.emplace_back(down[nxt[v]],down[v]);returnres;}public:G&g;introot,id;vector<int>size,depth,down,up,nxt,par;HeavyLightDecomposition(G&_g,int_root=0):g(_g),root(_root),id(0),size(g.size(),0),depth(g.size(),0),down(g.size(),-1),up(g.size(),-1),nxt(g.size(),root),par(g.size(),root){dfs_sz(root);dfs_hld(root);}pair<int,int>idx(inti)const{returnmake_pair(down[i],up[i]);}template<typenameF>voidpath_query(intu,intv,boolvertex,constF&f){intl=lca(u,v);for(auto&&[a,b]:ascend(u,l)){ints=a+1,t=b;s>t?f(t,s):f(s,t);}if(vertex)f(down[l],down[l]+1);for(auto&&[a,b]:descend(l,v)){ints=a,t=b+1;s>t?f(t,s):f(s,t);}}template<typenameF>voidpath_noncommutative_query(intu,intv,boolvertex,constF&f){intl=lca(u,v);for(auto&&[a,b]:ascend(u,l))f(a+1,b);if(vertex)f(down[l],down[l]+1);for(auto&&[a,b]:descend(l,v))f(a,b+1);}template<typenameF>voidsubtree_query(intu,boolvertex,constF&f){f(down[u]+int(!vertex),up[u]);}intlca(inta,intb){while(nxt[a]!=nxt[b]){if(down[a]<down[b])swap(a,b);a=par[nxt[a]];}returndepth[a]<depth[b]?a:b;}intdist(inta,intb){returndepth[a]+depth[b]-depth[lca(a,b)]*2;}};/**
* @brief Heavy Light Decomposition(重軽分解)
* @docs docs/tree/heavy-light-decomposition.md
*/#line 10 "tree/static-top-tree-vertex-based.hpp"
namespaceStaticTopTreeVertexBasedImpl{enumType{Vertex,Compress,Rake,Add_Edge,Add_Vertex};template<typenameG>structStaticTopTreeVertexBased{constHeavyLightDecomposition<G>&hld;vector<vector<int>>g;introot;// 元の木の rootinttt_root;// top tree の rootvector<int>P,L,R;vector<Type>T;StaticTopTreeVertexBased(constHeavyLightDecomposition<G>&_hld):hld(_hld){root=hld.root;g=rooted_tree(hld.g,root);intn=g.size();P.resize(n,-1),L.resize(n,-1),R.resize(n,-1);T.resize(n,Type::Vertex);build();}private:intadd(intl,intr,Typet){if(t==Type::Compressort==Type::Rake){assert(l!=-1andr!=-1);}if(t==Type::Add_Edge){assert(l!=-1andr==-1);}assert(t!=Type::Vertexandt!=Type::Add_Vertex);intk=P.size();P.push_back(-1),L.push_back(l),R.push_back(r),T.push_back(t);if(l!=-1)P[l]=k;if(r!=-1)P[r]=k;returnk;}intadd2(intk,intl,intr,Typet){assert(k<(int)g.size());assert(t==Type::Vertexort==Type::Add_Vertex);if(t==Type::Vertex){assert(l==-1andr==-1);}else{assert(l!=-1andr==-1);}P[k]=-1,L[k]=l,R[k]=r,T[k]=t;if(l!=-1)P[l]=k;if(r!=-1)P[r]=k;returnk;}pair<int,int>merge(constvector<pair<int,int>>&a,Typet){assert(!a.empty());if(a.size()==1)returna[0];intsum_s=0;for(auto&[_,s]:a)sum_s+=s;vector<pair<int,int>>b,c;for(auto&[i,s]:a){(sum_s>s?b:c).emplace_back(i,s);sum_s-=s*2;}auto[i,si]=merge(b,t);auto[j,sj]=merge(c,t);return{add(i,j,t),si+sj};}pair<int,int>compress(inti){vector<pair<int,int>>chs;while(true){chs.push_back(add_vertex(i));if(g[i].empty())break;i=g[i][0];}returnmerge(chs,Type::Compress);}pair<int,int>rake(inti){vector<pair<int,int>>chs;for(intj=1;j<(int)g[i].size();j++)chs.push_back(add_edge(g[i][j]));if(chs.empty())return{-1,0};returnmerge(chs,Type::Rake);}pair<int,int>add_edge(inti){auto[j,sj]=compress(i);return{add(j,-1,Type::Add_Edge),sj};}pair<int,int>add_vertex(inti){auto[j,sj]=rake(i);return{add2(i,j,-1,j==-1?Type::Vertex:Type::Add_Vertex),sj+1};}voidbuild(){auto[i,n]=compress(root);assert((int)g.size()==n);tt_root=i;}};template<typenameG,typenamePath,typenamePoint,typenameVertex,typenameCompress,typenameRake,typenameAdd_edge,typenameAdd_vertex>structDPonStaticTopTreeVertexBased{constStaticTopTreeVertexBased<G>tt;vector<Path>path;vector<Point>point;constVertexvertex;constCompresscompress;constRakerake;constAdd_edgeadd_edge;constAdd_vertexadd_vertex;DPonStaticTopTreeVertexBased(constHeavyLightDecomposition<G>&hld,constVertex&_vertex,constCompress&_compress,constRake&_rake,constAdd_edge&_add_edge,constAdd_vertex&_add_vertex):tt(hld),vertex(_vertex),compress(_compress),rake(_rake),add_edge(_add_edge),add_vertex(_add_vertex){intn=tt.P.size();path.resize(n),point.resize(n);dfs(tt.tt_root);}Pathget(){returnpath[tt.tt_root];}voidupdate(intk){while(k!=-1)_update(k),k=tt.P[k];}private:void_update(intk){if(tt.T[k]==Type::Vertex){path[k]=vertex(k);}elseif(tt.T[k]==Type::Compress){path[k]=compress(path[tt.L[k]],path[tt.R[k]]);}elseif(tt.T[k]==Type::Rake){point[k]=rake(point[tt.L[k]],point[tt.R[k]]);}elseif(tt.T[k]==Type::Add_Edge){point[k]=add_edge(path[tt.L[k]]);}else{path[k]=add_vertex(point[tt.L[k]],k);}}voiddfs(intk){if(tt.L[k]!=-1)dfs(tt.L[k]);if(tt.R[k]!=-1)dfs(tt.R[k]);_update(k);}};}// namespace StaticTopTreeVertexBasedImplusingStaticTopTreeVertexBasedImpl::DPonStaticTopTreeVertexBased;usingStaticTopTreeVertexBasedImpl::StaticTopTreeVertexBased;/*
// template
using Path = ;
using Point = ;
auto vertex = [&](int i) -> Path {
};
auto compress = [&](const Path& p, const Path& c) -> Path {
};
auto rake = [&](const Point& a, const Point& b) -> Point {
};
auto add_edge = [&](const Path& a) -> Point {
};
auto add_vertex = [&](const Point& a, int i) -> Path {
};
HeavyLightDecomposition hld{g};
DPonStaticTopTreeVertexBased<vector<vector<int>>, Path, Point,
decltype(vertex), decltype(compress), decltype(rake), decltype(add_edge),
decltype(add_vertex)>
dp(hld, vertex, compress, rake, add_edge, add_vertex);
*//**
* @brief Static Top Tree
*/