template <typename Weight, typename T>
struct WeightedReRooting {
struct edge {
int v;
Weight w;
edge() = default;
edge(int v, Weight w) : v(v), w(w) {}
};
using SubtreeMerge = function<T(T, T)>;
using PrefixSuffixMerge = function<T(T, T)>;
using Mapping = function<T(T, Weight)>;
vector<vector<edge>> g;
const SubtreeMerge f1;
const PrefixSuffixMerge f2;
const Mapping f3;
const T IE;
vector<T> subtree_dp, rerooting_dp;
WeightedReRooting(int V, const SubtreeMerge s, const PrefixSuffixMerge p, const Mapping m, const T I)
: g(V), f1(s), f2(p), f3(m), IE(I), subtree_dp(V, I), rerooting_dp(V, I) {}
void add_edge(int u, int v, Weight w){
g[u].emplace_back(v, w);
g[v].emplace_back(u, w);
}
void add_directed_edge(int u, int v, Weight w){
g[u].emplace_back(v, w);
}
void subtree_dfs(int from, int par){
for(auto& [to, weight] : g[from]){
if(to != par){
subtree_dfs(to, from);
subtree_dp[from] = f1(subtree_dp[from], f3(subtree_dp[to], weight));
}
}
}
void rerooting_function(int cur, T par_val, int par){
int V = g[cur].size();
vector<T> prefix(V + 1, IE), suffix(V + 1, IE);
for(int i = 0; i < V; ++i){
auto& [child, weight] = g[cur][i];
if(child == par) prefix[i + 1] = f1(prefix[i], f3(par_val, weight));
else prefix[i + 1] = f1(prefix[i], f3(subtree_dp[child], weight));
}
for(int i = V - 1; i >= 0; --i){
auto& [child, weight] = g[cur][i];
if(child == par) suffix[i] = f1(suffix[i + 1], f3(par_val, weight));
else suffix[i] = f1(suffix[i + 1], f3(subtree_dp[child], weight));
}
for(int i = 0; i < V; ++i){
auto& [child, weight] = g[cur][i];
if(child == par){
rerooting_dp[cur] = f1(subtree_dp[cur], f3(par_val, weight));
}
else{
rerooting_function(child, f2(prefix[i], suffix[i + 1]), cur);
}
}
}
vector<T> build(int root = 0){
subtree_dfs(root, -1);
rerooting_function(root, IE, -1);
rerooting_dp[root] = subtree_dp[root];
return rerooting_dp;
}
};