// 「T : 根が virtual である根付き木」に対応する情報を管理する
using T = ;
// 空の状態に対応する情報
T leaf = ;
// T 同士をマージ
auto f1 = [&](T x, T y) -> T {
};
// T の根に頂点 c および辺 c-p を追加する (p は virtual)
auto f2 = [&](T x, int c, int p) -> T {
};
Rerooting<T, decltype(g), decltype(f1), decltype(f2)> dp(g, f1, f2, leaf);
#pragma once
#include"../graph/graph-template.hpp"// Rerooting// f1(c1, c2) ... merge value of child node// f2(memo[i], chd, par) ... return value from child node to parent node// memo[i] ... result of subtree rooted i// dp[i] ... result of tree rooted itemplate<typenameT,typenameG,typenameF1,typenameF2>structRerooting{constG&g;constF1f1;constF2f2;vector<T>memo,dp;Tleaf;Rerooting(constG&_g,constF1_f1,constF2_f2,constT&_leaf):g(_g),f1(_f1),f2(_f2),memo(g.size()),dp(g.size()),leaf(_leaf){dfs(0,-1);dfs2(0,-1,T{});}constT&operator[](inti)const{returndp[i];}voiddfs(intcur,intpar){vector<T>chds;for(auto&dst:g[cur]){if(dst==par)continue;dfs(dst,cur);chds.push_back(f2(memo[dst],dst,cur));}if(chds.empty()){memo[cur]=leaf;}else{memo[cur]=chds[0];for(inti=1;i<(int)chds.size();i++){memo[cur]=f1(memo[cur],chds[i]);}}}voiddfs2(intcur,intpar,constT&pval){// get cumulative sumvector<T>buf;if(cur!=0)buf.push_back(pval);for(autodst:g[cur]){if(dst==par)continue;buf.push_back(f2(memo[dst],dst,cur));}vector<T>head(buf.size()),tail(buf.size());if(!buf.empty()){head[0]=buf[0];for(inti=1;i<(int)buf.size();i++){head[i]=f1(head[i-1],buf[i]);}tail.back()=buf.back();for(inti=(int)buf.size()-2;i>=0;i--){tail[i]=f1(tail[i+1],buf[i]);}}dp[cur]=head.empty()?leaf:head.back();intidx=cur==0?0:1;for(auto&dst:g[cur]){if(dst==par)continue;Tval;boolfirst=idx==0;boollast=idx+1==(int)head.size();if(firstandlast){val=leaf;}elseif(first){val=tail[idx+1];}elseif(last){val=head[idx-1];}else{val=f1(head[idx-1],tail[idx+1]);}dfs2(dst,cur,f2(val,cur,dst));idx++;}}};/**
* @brief Rerooting(全方位木DP)
* @docs docs/tree/rerooting.md
*/
#line 2 "tree/rerooting.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/rerooting.hpp"
// Rerooting// f1(c1, c2) ... merge value of child node// f2(memo[i], chd, par) ... return value from child node to parent node// memo[i] ... result of subtree rooted i// dp[i] ... result of tree rooted itemplate<typenameT,typenameG,typenameF1,typenameF2>structRerooting{constG&g;constF1f1;constF2f2;vector<T>memo,dp;Tleaf;Rerooting(constG&_g,constF1_f1,constF2_f2,constT&_leaf):g(_g),f1(_f1),f2(_f2),memo(g.size()),dp(g.size()),leaf(_leaf){dfs(0,-1);dfs2(0,-1,T{});}constT&operator[](inti)const{returndp[i];}voiddfs(intcur,intpar){vector<T>chds;for(auto&dst:g[cur]){if(dst==par)continue;dfs(dst,cur);chds.push_back(f2(memo[dst],dst,cur));}if(chds.empty()){memo[cur]=leaf;}else{memo[cur]=chds[0];for(inti=1;i<(int)chds.size();i++){memo[cur]=f1(memo[cur],chds[i]);}}}voiddfs2(intcur,intpar,constT&pval){// get cumulative sumvector<T>buf;if(cur!=0)buf.push_back(pval);for(autodst:g[cur]){if(dst==par)continue;buf.push_back(f2(memo[dst],dst,cur));}vector<T>head(buf.size()),tail(buf.size());if(!buf.empty()){head[0]=buf[0];for(inti=1;i<(int)buf.size();i++){head[i]=f1(head[i-1],buf[i]);}tail.back()=buf.back();for(inti=(int)buf.size()-2;i>=0;i--){tail[i]=f1(tail[i+1],buf[i]);}}dp[cur]=head.empty()?leaf:head.back();intidx=cur==0?0:1;for(auto&dst:g[cur]){if(dst==par)continue;Tval;boolfirst=idx==0;boollast=idx+1==(int)head.size();if(firstandlast){val=leaf;}elseif(first){val=tail[idx+1];}elseif(last){val=head[idx-1];}else{val=f1(head[idx-1],tail[idx+1]);}dfs2(dst,cur,f2(val,cur,dst));idx++;}}};/**
* @brief Rerooting(全方位木DP)
* @docs docs/tree/rerooting.md
*/