library_checker/tree/
point_set_tree_path_composite_sum_fixed_root.rs1use competitive::prelude::*;
2use competitive::{
3 algebra::{Associative, Magma, Unital},
4 graph::TreeGraphScanner,
5 num::{One, Zero, mint_basic::MInt998244353 as M},
6 tree::MonoidCluster,
7};
8
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10struct Point {
11 sum: M,
12 cnt: u32,
13}
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
16struct Path {
17 a: M,
18 b: M,
19 sum: M,
20 cnt: u32,
21}
22
23struct PointMonoid;
24impl Magma for PointMonoid {
25 type T = Point;
26 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
27 Point {
28 sum: x.sum + y.sum,
29 cnt: x.cnt + y.cnt,
30 }
31 }
32}
33impl Unital for PointMonoid {
34 fn unit() -> Self::T {
35 Point {
36 sum: M::zero(),
37 cnt: 0,
38 }
39 }
40}
41impl Associative for PointMonoid {}
42
43struct PathMonoid;
44impl Magma for PathMonoid {
45 type T = Path;
46 fn operate(x: &Self::T, y: &Self::T) -> Self::T {
47 Path {
48 a: x.a * y.a,
49 b: x.b + x.a * y.b,
50 sum: x.sum + x.a * y.sum + x.b * M::new_unchecked(y.cnt),
51 cnt: x.cnt + y.cnt,
52 }
53 }
54}
55impl Unital for PathMonoid {
56 fn unit() -> Self::T {
57 Path {
58 a: M::one(),
59 b: M::zero(),
60 sum: M::zero(),
61 cnt: 0,
62 }
63 }
64}
65impl Associative for PathMonoid {}
66
67struct Dp;
68
69impl MonoidCluster for Dp {
70 type Vertex = M;
71 type Edge = (M, M);
72 type PointMonoid = PointMonoid;
73 type PathMonoid = PathMonoid;
74
75 fn add_vertex(point: &Point, vertex: &M, parent_edge: Option<&(M, M)>) -> Path {
76 let cnt = point.cnt + 1;
77 let subtotal = point.sum + *vertex;
78 let (a, b) = parent_edge.copied().unwrap_or((M::one(), M::zero()));
79 Path {
80 a,
81 b,
82 sum: a * subtotal + b * M::new_unchecked(cnt),
83 cnt,
84 }
85 }
86
87 fn add_edge(path: &Path) -> Point {
88 Point {
89 sum: path.sum,
90 cnt: path.cnt,
91 }
92 }
93}
94
95competitive::define_enum_scan! {
96 enum Query: usize {
97 0 => SetVertex { v: usize, x: M }
98 1 => SetEdge { e: usize, a: M, b: M }
99 }
100}
101
102#[verify::library_checker("point_set_tree_path_composite_sum_fixed_root")]
103pub fn point_set_tree_path_composite_sum_fixed_root(reader: impl Read, writer: impl Write) {
104 prepare_io!(reader, writer);
105 sc!(n,
106 q,
107 value: [M; n],
108 (graph, edges): @TreeGraphScanner::<usize, (M, M)>::new(n));
109
110 let top_tree = graph.static_top_tree(0);
111 let mut dp = top_tree.dp::<Dp>(value, edges);
112
113 for _ in 0..q {
114 sc!(query: Query);
115 match query {
116 Query::SetVertex { v, x } => {
117 dp.set_vertex(v, x);
118 pp!(dp.fold_all().sum);
119 }
120 Query::SetEdge { e, a, b } => {
121 dp.set_edge(e, (a, b));
122 pp!(dp.fold_all().sum);
123 }
124 }
125 }
126}