1use competitive::prelude::*;
2#[doc(no_inline)]
3pub use competitive::{
4 algebra::{Associative, Magma, Unital},
5 graph::TreeGraphScanner,
6 num::{One, Zero, mint_basic::MInt998244353},
7 tree::MonoidCluster,
8};
9
10type MInt = MInt998244353;
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq)]
13struct Point {
14 sum: MInt,
15 cnt: MInt,
16}
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19struct Path {
20 a: MInt,
21 b: MInt,
22 sum: MInt,
23 cnt: MInt,
24}
25
26struct PointMonoid;
27impl Magma for PointMonoid {
28 type T = Point;
29 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
30 Point {
31 sum: x.sum + y.sum,
32 cnt: x.cnt + y.cnt,
33 }
34 }
35}
36impl Unital for PointMonoid {
37 fn unit() -> Self::T {
38 Point {
39 sum: MInt::zero(),
40 cnt: MInt::zero(),
41 }
42 }
43}
44impl Associative for PointMonoid {}
45
46struct PathMonoid;
47impl Magma for PathMonoid {
48 type T = Path;
49 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
50 Path {
51 a: x.a * y.a,
52 b: x.b + x.a * y.b,
53 sum: x.sum + x.a * y.sum + x.b * y.cnt,
54 cnt: x.cnt + y.cnt,
55 }
56 }
57}
58impl Unital for PathMonoid {
59 fn unit() -> Self::T {
60 Path {
61 a: MInt::one(),
62 b: MInt::zero(),
63 sum: MInt::zero(),
64 cnt: MInt::zero(),
65 }
66 }
67}
68impl Associative for PathMonoid {}
69
70#[derive(Clone, Copy, Debug, PartialEq, Eq)]
71struct PathPair {
72 forward: Path,
73 reverse: Path,
74}
75
76struct PathPairMonoid;
77impl Magma for PathPairMonoid {
78 type T = PathPair;
79 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
80 PathPair {
81 forward: PathMonoid::operate(&x.forward, &y.forward),
82 reverse: PathMonoid::operate(&y.reverse, &x.reverse),
83 }
84 }
85}
86impl Unital for PathPairMonoid {
87 fn unit() -> Self::T {
88 PathPair {
89 forward: PathMonoid::unit(),
90 reverse: PathMonoid::unit(),
91 }
92 }
93}
94impl Associative for PathPairMonoid {}
95
96struct Dp;
97
98impl MonoidCluster for Dp {
99 type Vertex = MInt;
100 type Edge = (MInt, MInt);
101 type PointMonoid = PointMonoid;
102 type PathMonoid = PathPairMonoid;
103
104 fn add_vertex(point: &Point, vertex: &MInt, parent_edge: Option<&(MInt, MInt)>) -> PathPair {
105 let cnt = point.cnt + MInt::one();
106 let subtotal = point.sum + *vertex;
107 let (a, b) = parent_edge.copied().unwrap_or((MInt::one(), MInt::zero()));
108 PathPair {
109 forward: Path {
110 a,
111 b,
112 sum: a * subtotal + b * cnt,
113 cnt,
114 },
115 reverse: Path {
116 a,
117 b,
118 sum: subtotal,
119 cnt,
120 },
121 }
122 }
123
124 fn add_edge(path: &PathPair) -> Point {
125 Point {
126 sum: path.forward.sum,
127 cnt: path.forward.cnt,
128 }
129 }
130}
131
132competitive::define_enum_scan! {
133 enum Query: usize {
134 0 => SetVertex { v: usize, x: MInt, r: usize }
135 1 => SetEdge { e: usize, a: MInt, b: MInt, r: usize }
136 }
137}
138
139#[verify::library_checker("point_set_tree_path_composite_sum")]
140pub fn point_set_tree_path_composite_sum(reader: impl Read, mut writer: impl Write) {
141 let s = read_all_unchecked(reader);
142 let mut scanner = Scanner::new(&s);
143 scan!(
144 scanner,
145 n,
146 q,
147 value: [MInt; n],
148 (graph, edges): @TreeGraphScanner::<usize, (MInt, MInt)>::new(n)
149 );
150
151 let top_tree = graph.static_top_tree(0);
152 let mut dp = top_tree.dp::<Dp>(value, edges);
153
154 for _ in 0..q {
155 scan!(scanner, query: Query);
156 match query {
157 Query::SetVertex { v, x, r } => {
158 dp.set_vertex(v, x);
159 writeln!(writer, "{}", dp.fold_path(r).reverse.sum).ok();
160 }
161 Query::SetEdge { e, a, b, r } => {
162 dp.set_edge(e, (a, b));
163 writeln!(writer, "{}", dp.fold_path(r).reverse.sum).ok();
164 }
165 }
166 }
167}