This documentation is automatically generated by online-judge-tools/verification-helper
#define PROBLEM "https://judge.yosupo.jp/problem/tree_path_composite_sum"
#include "../Library/Template.hpp"
#include "../Library/modint.hpp"
#include "../Library/Tree/RerootingDP.hpp"
struct Affine{
Affine() = default;
Affine(mint b, mint c) : b(b), c(c){}
mint b{1}, c{0};
friend ostream &operator<<(ostream &os, const Affine &p) {
return os << "{" << p.b << ", " << p.c << "}";
}
};
struct Monoid{
Monoid() = default;
Monoid(mint v, mint c) : val(v), cnt(c){}
mint val{0}, cnt{0};
friend ostream &operator<<(ostream &os, const Monoid &p) {
return os << "{" << p.val << ", " << p.cnt << "}";
}
};
int main(){
cin.tie(0)->sync_with_stdio(false);
int N; cin >> N;
vector<mint> a(N); cin >> a;
Graph<Affine> T(N);
for(int i = 0; i < N - 1; ++i){
int u, v; cin >> u >> v;
mint b, c; cin >> b >> c;
T.AddUndirectedEdge(u, v, Affine(b, c));
}
RerootingDP<Affine, Monoid> dp(
T,
[](Monoid l, Monoid r, Vertex i){
return Monoid(l.val + r.val, l.cnt + r.cnt);
},
[&](Monoid x, Affine m, Vertex i){
return Monoid(m.b * (a[i] + x.val) + (x.cnt + 1) * m.c, x.cnt + 1);
},
[&](Monoid x, Vertex i){
return Monoid(x.val + a[i], x.cnt + 1);
},
Monoid()
);
for(int i = 0; i < N; ++i){
cout << dp[i].val << " ";
}
}#line 1 "verify/LC-TreePathCompositeSum.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/tree_path_composite_sum"
#line 2 "Library/Template.hpp"
#line 2 "Library/Common.hpp"
/**
* @file Common.hpp
*/
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cstdint>
#include <deque>
#include <functional>
#include <iomanip>
#include <iostream>
#include <limits>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;
using ll = int64_t;
using ull = uint64_t;
constexpr const ll INF = (1LL << 62) - (3LL << 30) - 1;
#line 4 "Library/Template.hpp"
inline bool YnPrint(bool flag){cout << (flag ? "Yes" : "No") << '\n'; return flag;}
inline bool YNPrint(bool flag){cout << (flag ? "YES" : "NO") << '\n'; return flag;}
template<typename Container>
inline void Sort(Container &container){sort(container.begin(), container.end());}
template<typename Container>
inline void ReverseSort(Container &container){sort(container.rbegin(), container.rend());}
template<typename Container>
inline void Reverse(Container &container){reverse(container.begin(), container.end());}
template<typename Value>
inline int PopCount(const Value &value){return __builtin_popcount(value);}
template<typename Value>
inline Value Floor(Value numerator, Value denominator){if(denominator < 0) numerator *= -1, denominator *= -1; return numerator < 0 ? (numerator + 1) / denominator - 1 : numerator / denominator;}
template<typename Value>
inline Value Ceil(Value numerator, Value denominator){if(denominator < 0) numerator *= -1, denominator *= -1; return numerator > 0 ? (numerator - 1) / denominator + 1 : numerator / denominator;}
template<typename Value>
inline int LowerBoundIndex(const vector<Value> &container, const Value &value){return distance(container.begin(), lower_bound(container.begin(), container.end(), value));}
template<typename Value>
inline int UpperBoundIndex(const vector<Value> &container, const Value &value){return distance(container.begin(), upper_bound(container.begin(), container.end(), value));}
template<typename Value>
inline bool Between(const Value &lower, const Value &x, const Value &higher){return lower <= x && x <= higher;}
template<typename Value>
inline bool InGrid(const Value &y, const Value &x, const Value &ymax, const Value &xmax){return Between(0, y, ymax - 1) && Between(0, x, xmax - 1);}
template<typename Value>
inline Value Median(const Value &a, const Value &b, const Value &c){return Between(b, a, c) || Between(c, a, b) ? a : (Between(a, b, c) || Between(c, b, a) ? b : c);}
template<typename Value>
inline Value Except(Value &src, Value &cond, Value &excp){return (src == cond ? excp : src);}
template<class Value>
bool chmin(Value &src, const Value &cmp){if(src > cmp){src = cmp; return true;} return false;}
template<class Value>
bool chmax(Value &src, const Value &cmp){if(src < cmp){src = cmp; return true;} return false;}
template<typename Value>
inline Value min(vector<Value> &v){return *min_element((v).begin(), (v).end());}
template<typename Value>
inline Value max(vector<Value> &v){return *max_element((v).begin(), (v).end());}
const int dx4[4] = {1, 0, -1, 0};
const int dy4[4] = {0, -1, 0, 1};
const int dx8[8] = {1, 1, 0, -1, -1, -1, 0, 1};
const int dy8[8] = {0, -1, -1, -1, 0, 1, 1, 1};
vector<pair<int, int>> adjacent(int current_y, int current_x, int max_y, int max_x, bool dir_8 = false){
vector<pair<int, int>> ret;
for(int d = 0; d < 4 * (1 + dir_8); ++d){
int next_y = current_y + (dir_8 ? dy8[d] : dy4[d]);
int next_x = current_x + (dir_8 ? dx8[d] : dx4[d]);
if(InGrid(next_y, next_x, max_y, max_x)){
ret.emplace_back(next_y, next_x);
}
}
return ret;
}
template <typename T1, typename T2>
ostream &operator<<(ostream &os, const pair<T1, T2> &p){
os << p.first << " " << p.second;
return os;
}
template <typename T1, typename T2>
istream &operator>>(istream &is, pair<T1, T2> &p){
is >> p.first >> p.second;
return is;
}
template <typename T>
ostream &operator<<(ostream &os, vector<T> &v){
for (int i = 0; i < v.size(); ++i){
os << v[i] << (i + 1 != v.size() ? " " : "");
}
return os;
}
template <typename T>
ostream &operator<<(ostream &os, vector<vector<T>> &v){
for (int i = 0; i < v.size(); ++i){
os << v[i] << (i + 1 != v.size() ? "\n" : "");
}
return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
for (int i = 0; i < v.size(); ++i) is >> v[i];
return is;
}
template <typename T>
ostream &operator<<(ostream &os, set<T> &v){
for (auto &u : v){
os << u << " ";
}
return os;
}
template<typename T1, typename T2>
vector<pair<T1, T2>> AssembleVectorPair(vector<T1> &v1, vector<T2> &v2){
assert(v1.size() == v2.size());
vector<pair<T1, T2>> v;
for(int i = 0; i < v1.size(); ++i) v.push_back({v1[i], v2[i]});
return v;
}
template<typename T1, typename T2>
pair<vector<T1>, vector<T2>> DisassembleVectorPair(vector<pair<T1, T2>> &v){
vector<T1> v1;
vector<T2> v2;
transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return p.first;});
transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return p.second;});
return {v1, v2};
}
template<typename T1, typename T2, typename T3>
tuple<vector<T1>, vector<T2>, vector<T3>> DisassembleVectorTuple(vector<tuple<T1, T2, T3>> &v){
vector<T1> v1;
vector<T2> v2;
vector<T3> v3;
transform(v.begin(), v.end(), back_inserter(v1), [](auto p){return get<0>(p);});
transform(v.begin(), v.end(), back_inserter(v2), [](auto p){return get<1>(p);});
transform(v.begin(), v.end(), back_inserter(v3), [](auto p){return get<2>(p);});
return {v1, v2, v3};
}
template<typename T1 = int, typename T2 = T1>
pair<vector<T1>, vector<T2>> InputVectorPair(int size){
vector<pair<T1, T2>> v(size);
for(auto &[p, q] : v) cin >> p >> q;
return DisassembleVectorPair(v);
}
template<typename T1 = int, typename T2 = T1, typename T3 = T1>
tuple<vector<T1>, vector<T2>, vector<T3>> InputVectorTuple(int size){
vector<tuple<T1, T2, T3>> v(size);
for(auto &[p, q, r] : v) cin >> p >> q >> r;
return DisassembleVectorTuple(v);
}
#line 2 "Library/modint.hpp"
/**
* @file modint.hpp
* @author log K (lX57)
* @brief modint
* @version 1.0
* @date 2023-08-24
*/
#line 12 "Library/modint.hpp"
using namespace std;
const int mod998 = 998244353;
const int mod107 = 1000000007;
template< int mod >
struct ModInt {
int x;
ModInt() : x(0) {}
ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
ModInt &operator+=(const ModInt &p) {
if((x += p.x) >= mod) x -= mod;
return *this;
}
ModInt &operator-=(const ModInt &p) {
if((x += mod - p.x) >= mod) x -= mod;
return *this;
}
ModInt &operator*=(const ModInt &p) {
x = (int) (1LL * x * p.x % mod);
return *this;
}
ModInt &operator/=(const ModInt &p) {
*this *= p.inverse();
return *this;
}
ModInt operator-() const { return ModInt(-x); }
ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
bool operator==(const ModInt &p) const { return x == p.x; }
bool operator!=(const ModInt &p) const { return x != p.x; }
ModInt inverse() const {
int a = x, b = mod, u = 1, v = 0, t;
while(b > 0) {
t = a / b;
swap(a -= t * b, b);
swap(u -= t * v, v);
}
return ModInt(u);
}
ModInt pow(int64_t n) const {
if(n == 0) return ModInt(1);
ModInt ret(1), mul(x);
while(n > 0) {
if(n & 1) ret *= mul;
mul *= mul;
n >>= 1;
}
return ret;
}
friend ostream &operator<<(ostream &os, const ModInt &p) {
return os << p.x;
}
friend istream &operator>>(istream &is, ModInt &a) {
int64_t t;
is >> t;
a = ModInt< mod >(t);
return (is);
}
static int get_mod() { return mod; }
};
using mint = ModInt<mod998>;
using mint107 = ModInt<mod107>;
using vm = vector<mint>;
using vvm = vector<vector<mint>>;
using vm107 = vector<mint107>;
using vvm107 = vector<vector<mint107>>;
#line 2 "Library/Tree/Tree.hpp"
#line 2 "Library/Graph/Graph.hpp"
#line 4 "Library/Graph/Graph.hpp"
using Vertex = int;
template<typename WeightType = int32_t>
struct Edge{
public:
Edge() = default;
Edge(Vertex from_, Vertex to_, WeightType weight_ = 1, int idx_ = -1) :
from(from_), to(to_), cost(weight_), idx(idx_){}
bool operator<(const Edge<WeightType> &e) const {return cost < e.cost;}
operator int() const {return to;}
Vertex from, to;
WeightType cost;
int idx;
};
template<typename WeightType = int32_t>
class Graph{
public:
Graph() = default;
Graph(int V) : edge_size_(0), adjacent_list_(V){}
inline void AddUndirectedEdge(Vertex u, Vertex v, WeightType w = 1){
int idx = edge_size_++;
adjacent_list_[u].push_back(Edge<WeightType>(u, v, w, idx));
adjacent_list_[v].push_back(Edge<WeightType>(v, u, w, idx));
}
inline void AddDirectedEdge(Vertex u, Vertex v, WeightType w = 1){
int idx = edge_size_++;
adjacent_list_[u].push_back(Edge<WeightType>(u, v, w, idx));
}
inline size_t VertexSize() const {
return adjacent_list_.size();
}
inline size_t EdgeSize() const {
return edge_size_;
}
inline vector<Edge<WeightType>> &operator[](const Vertex v){
return adjacent_list_[v];
}
inline const vector<Edge<WeightType>> &operator[](const Vertex v) const {
return adjacent_list_[v];
}
private:
size_t edge_size_;
vector<vector<Edge<WeightType>>> adjacent_list_;
};
template<typename WeightType = int32_t>
Graph<WeightType> InputGraph(int N, int M, int padding = -1, bool weighted = false, bool directed = false){
Graph<WeightType> G(N);
for(int i = 0; i < M; ++i){
Vertex u, v; WeightType w = 1;
cin >> u >> v, u += padding, v += padding;
if(weighted) cin >> w;
if(directed) G.AddDirectedEdge(u, v, w);
else G.AddUndirectedEdge(u, v, w);
}
return G;
}
#line 4 "Library/Tree/Tree.hpp"
template<typename WeightType = int32_t>
Graph<WeightType> InputTree(int V, int padding = -1, bool weighted = false){
Graph<WeightType> G(V);
for(int i = 0; i < V - 1; ++i){
Vertex u, v; WeightType w = 1;
cin >> u >> v, u += padding, v += padding;
if(weighted) cin >> w;
G.AddUndirectedEdge(u, v, w);
}
return G;
}
template<typename WeightType = int32_t>
Graph<WeightType> InputRootedTreeChild(int V, int padding = -1){
Graph<WeightType> G(V);
for(Vertex u = 0; u < V; ++u){
int k; cin >> k;
for(int i = 0; i < k; ++i){
Vertex v; cin >> v, v += padding;
G.AddUndirectedEdge(u, v);
}
}
return G;
}
template<typename WeightType = int32_t>
Graph<WeightType> InputRootedTreeParent(int V, int padding = -1){
Graph<WeightType> G(V);
for(Vertex u = 1; u < V; ++u){
Vertex v; cin >> v, v += padding;
G.AddUndirectedEdge(u, v);
}
return G;
}
template<typename WeightType = int32_t>
vector<vector<Vertex>> RootedTreeAdjacentList(const Graph<WeightType> &T, const Vertex r = 0){
int V = T.VertexSize();
vector<vector<Vertex>> ret(V);
auto rec = [&](auto &self, Vertex u, Vertex p) -> void {
for(Vertex v : T[u]){
if(v == p) continue;
ret[u].push_back(v);
self(self, v, u);
}
};
rec(rec, r, -1);
return ret;
}
template<typename WeightType>
vector<Vertex> CalculateTreeParent(Graph<WeightType> &T, Vertex r = 0){
int V = T.VertexSize();
vector<Vertex> ret(V, -1);
auto rec = [&](auto &self, Vertex u) -> void {
for(Vertex v : T[u]){
if(v == ret[u]) continue;
ret[v] = u;
self(self, v);
}
};
rec(rec, r);
return ret;
}
template<typename WeightType>
vector<WeightType> CalculateTreeCost(Graph<WeightType> &T, Vertex r = 0){
int V = T.VertexSize();
vector<WeightType> ret(V);
auto rec = [&](auto &self, Vertex u, Vertex p) -> void {
for(const Edge<WeightType> &e : T[u]){
Vertex v = e.to;
if(v == p) continue;
ret[v] = e.cost;
self(self, v, u);
}
};
rec(rec, r, -1);
return ret;
}
template<typename WeightType>
vector<int> CalculateTreeDepth(Graph<WeightType> &T, Vertex r = 0){
int V = T.VertexSize();
vector<int> ret(V, 0);
auto rec = [&](auto &self, Vertex u, Vertex p, int d) -> void {
ret[u] = d;
for(Vertex v : T[u]){
if(v == p) continue;
self(self, v, u, d + 1);
}
};
rec(rec, r, -1, 0);
return ret;
}
template<typename WeightType>
vector<WeightType> CalculateTreeDistance(Graph<WeightType> &T, Vertex r = 0){
int V = T.VertexSize();
vector<WeightType> ret(V, WeightType(INF));
auto rec = [&](auto &self, Vertex u) -> void {
for(const Edge<WeightType> &e : T[u]){
if(ret[e.to] > ret[u] + e.cost){
ret[e.to] = ret[u] + e.cost;
self(self, e.to);
}
}
};
ret[r] = 0;
rec(rec, r);
return ret;
}
template<typename WeightType>
vector<int> CalculateSubtreeSize(Graph<WeightType> &tree, Vertex r = 0){
int V = tree.VertexSize();
vector<int> ret(V, 1);
auto rec = [&](auto self, Vertex u, Vertex p) -> int {
for(const int v : tree[u]){
if(v == p) continue;
ret[u] += self(self, v, u);
}
return ret[u];
};
rec(rec, r, -1);
return ret;
}
#line 2 "Library/Tree/RerootingDP.hpp"
template<typename WeightType, typename Monoid>
class RerootingDP{
public:
using F = function<Monoid(Monoid, Monoid, Vertex)>;
using G = function<Monoid(Monoid, WeightType, Vertex)>;
using H = function<Monoid(Monoid, Vertex)>;
using Fsub = function<Monoid(Monoid, Monoid)>;
using Gsub = function<Monoid(Monoid, WeightType)>;
RerootingDP(Graph<WeightType> &tree, Fsub merge, Gsub add, const Monoid monoid_identity, Vertex r = 0) :
T(tree), n(tree.VertexSize()), parent(CalculateTreeParent(tree, r)), cost(CalculateTreeCost(tree, r)), child(RootedTreeAdjacentList(tree, r)),
merge_sub_(merge), add_sub_(add), id_(monoid_identity){
merge_ = [&](Monoid x, Monoid y, Vertex i){return merge_sub_(x, y);};
add_ = [&](Monoid x, WeightType y, Vertex i){return add_sub_(x, y);};
finalize_ = [](Monoid x, Vertex i){return x;};
solve(r);
}
RerootingDP(Graph<WeightType> &tree, F merge, G add, H finalize, const Monoid monoid_identity, Vertex r = 0) :
T(tree), n(tree.VertexSize()), parent(CalculateTreeParent(tree, r)), cost(CalculateTreeCost(tree, r)), child(RootedTreeAdjacentList(tree, r)),
merge_(merge), add_(add), finalize_(finalize), id_(monoid_identity){
solve(r);
}
vector<Monoid> &GetAllAnswer(){
return dp_;
}
Monoid operator[](Vertex v){
return dp_[v];
}
const Monoid operator[](Vertex v) const {
return dp_[v];
}
void Print() const {
cerr << "# dp table :";
for(int i = 0; i < n; ++i){
cerr << " " << dp_[i];
}
cerr << '\n';
cerr << "# subtree_dp table" << '\n';
for(int i = 0; i < n; ++i){
cerr << "# vertex " << i << '\n';
cerr << "# subtree_dp :";
for(int j = 0; j < subtree_dp_[i].size(); ++j){
cerr << " " << subtree_dp_[i][j];
}
cerr << '\n';
cerr << "# left_cum :";
for(int j = 0; j < left_cum_[i].size(); ++j){
cerr << " " << left_cum_[i][j];
}
cerr << '\n';
cerr << "# right_cum :";
for(int j = 0; j < right_cum_[i].size(); ++j){
cerr << " " << right_cum_[i][j];
}
cerr << '\n';
}
}
private:
Graph<WeightType> &T;
int n;
vector<Vertex> parent;
vector<WeightType> cost;
vector<vector<Vertex>> child;
vector<Monoid> dp_;
vector<vector<Monoid>> subtree_dp_, left_cum_, right_cum_;
const Monoid id_;
F merge_;
G add_;
H finalize_;
const Fsub merge_sub_;
const Gsub add_sub_;
Monoid dfs(Vertex v, bool root = false){
Monoid ret = id_;
for(auto u : child[v]){
Monoid res = dfs(u);
subtree_dp_[v].push_back(res);
ret = merge_(ret, res, v);
}
if(root) ret = finalize_(ret, v);
else ret = add_(ret, cost[v], v);
return ret;
}
void solve(Vertex r){
dp_.resize(n, id_);
subtree_dp_.resize(n, vector<Monoid>{id_});
left_cum_.resize(n);
right_cum_.resize(n);
dp_[r] = dfs(r, true);
int root_size = subtree_dp_[r].size();
left_cum_[r].resize(root_size + 1);
left_cum_[r].front() = id_;
for(int i = 1; i < root_size; ++i){
left_cum_[r][i] = merge_(left_cum_[r][i - 1], subtree_dp_[r][i], r);
}
right_cum_[r].resize(root_size + 1);
right_cum_[r].back() = id_;
for(int i = root_size - 1; i - 1 >= 0; --i){
right_cum_[r][i] = merge_(right_cum_[r][i + 1], subtree_dp_[r][i], r);
}
queue<tuple<int, int, int>> que;
for(int i = 0; i < child[r].size(); ++i){
que.push({child[r][i], r, i + 1});
}
while(que.size()){
auto [v, p, idx] = que.front(); que.pop();
Monoid ret = id_;
ret = merge_(ret, left_cum_[p][idx - 1], v);
ret = merge_(ret, right_cum_[p][idx + 1], v);
ret = add_(ret, cost[v], p);
subtree_dp_[v].push_back(ret);
for(int i = 1; i + 1 < subtree_dp_[v].size(); ++i){
ret = merge_(ret, subtree_dp_[v][i], v);
}
dp_[v] = finalize_(ret, v);
int c = subtree_dp_[v].size();
left_cum_[v].resize(c + 1);
left_cum_[v][0] = id_;
for(int i = 1; i < c; ++i){
left_cum_[v][i] = merge_(left_cum_[v][i - 1], subtree_dp_[v][i], v);
}
right_cum_[v].resize(c + 1);
right_cum_[v].back() = id_;
for(int i = c - 1; i - 1 >= 0; --i){
right_cum_[v][i] = merge_(right_cum_[v][i + 1], subtree_dp_[v][i], v);
}
for(int i = 0; i < child[v].size(); ++i){
que.push({child[v][i], v, i + 1});
}
}
}
};
#line 6 "verify/LC-TreePathCompositeSum.test.cpp"
struct Affine{
Affine() = default;
Affine(mint b, mint c) : b(b), c(c){}
mint b{1}, c{0};
friend ostream &operator<<(ostream &os, const Affine &p) {
return os << "{" << p.b << ", " << p.c << "}";
}
};
struct Monoid{
Monoid() = default;
Monoid(mint v, mint c) : val(v), cnt(c){}
mint val{0}, cnt{0};
friend ostream &operator<<(ostream &os, const Monoid &p) {
return os << "{" << p.val << ", " << p.cnt << "}";
}
};
int main(){
cin.tie(0)->sync_with_stdio(false);
int N; cin >> N;
vector<mint> a(N); cin >> a;
Graph<Affine> T(N);
for(int i = 0; i < N - 1; ++i){
int u, v; cin >> u >> v;
mint b, c; cin >> b >> c;
T.AddUndirectedEdge(u, v, Affine(b, c));
}
RerootingDP<Affine, Monoid> dp(
T,
[](Monoid l, Monoid r, Vertex i){
return Monoid(l.val + r.val, l.cnt + r.cnt);
},
[&](Monoid x, Affine m, Vertex i){
return Monoid(m.b * (a[i] + x.val) + (x.cnt + 1) * m.c, x.cnt + 1);
},
[&](Monoid x, Vertex i){
return Monoid(x.val + a[i], x.cnt + 1);
},
Monoid()
);
for(int i = 0; i < N; ++i){
cout << dp[i].val << " ";
}
}