1use crate::math::linear::*;
4use crate::misc::range::range_bounds_to_range;
5use crate::num::one_zero::Zero;
6use crate::trait_alias;
7use std::ops::{Add, AddAssign, Mul, RangeBounds};
8
9trait_alias!(
10 Elem: Copy + Zero + Add<Output = Self> + Mul<Output = Self> + AddAssign + PartialEq + From<u32>
12);
13
14pub struct SegtreeLinearAddRangeSum<T> {
16 data: Vec<T>,
17 lazy: Vec<(T, T)>,
18 hsize: usize,
19 original_size: usize,
20}
21
22impl<T: Elem> SegtreeLinearAddRangeSum<T> {
23 pub fn new(n: usize) -> Self {
27 let hsize = n.next_power_of_two();
28
29 Self {
30 data: vec![T::zero(); hsize * 2],
31 lazy: vec![(T::zero(), T::zero()); hsize * 2],
32 hsize,
33 original_size: n,
34 }
35 }
36
37 fn _add(a: (T, T), b: (T, T)) -> (T, T) {
38 (a.0 + b.0, a.1 + b.1)
39 }
40
41 fn _propagate(&mut self, i: usize, l: usize, r: usize) {
42 if self.lazy[i] == (T::zero(), T::zero()) {
43 return;
44 }
45 if i < self.hsize {
46 let mut t = self.lazy[i];
47 self.lazy[i << 1] = Self::_add(t, self.lazy[i << 1]);
48 t.0 += t.1 * T::from(((r - l) / 2) as u32);
49 self.lazy[(i << 1) | 1] = Self::_add(t, self.lazy[(i << 1) | 1]);
50 }
51 let len = r - l;
52 let (s, d) = self.lazy[i];
53
54 self.data[i] += s * T::from(len as u32) + d * T::from(((len - 1) * len / 2) as u32);
55 self.lazy[i] = (T::zero(), T::zero());
56 }
57
58 fn _update(&mut self, i: usize, l: usize, r: usize, s: usize, t: usize, a: T, b: T) -> T {
59 self._propagate(i, l, r);
60 if r <= s || t <= l {
61 self.data[i]
62 } else if s <= l && r <= t {
63 self.lazy[i] = Self::_add(self.lazy[i], (a * T::from(l as u32) + b, a));
64 self._propagate(i, l, r);
65 self.data[i]
66 } else {
67 let mid = (l + r) / 2;
68 self.data[i] = self._update(i << 1, l, mid, s, t, a, b)
69 + self._update((i << 1) | 1, mid, r, s, t, a, b);
70 self.data[i]
71 }
72 }
73
74 pub fn update(&mut self, range: impl RangeBounds<usize>, linear: Linear<T>) {
76 let (start, end) = range_bounds_to_range(range, 0, self.original_size);
77 self._update(1, 0, self.hsize, start, end, linear.a, linear.b);
78 }
79
80 fn _fold(&mut self, i: usize, l: usize, r: usize, x: usize, y: usize) -> T {
81 self._propagate(i, l, r);
82 if r <= x || y <= l {
83 T::zero()
84 } else if x <= l && r <= y {
85 self.data[i]
86 } else {
87 let mid = (l + r) / 2;
88 self._fold(i << 1, l, mid, x, y) + self._fold((i << 1) | 1, mid, r, x, y)
89 }
90 }
91
92 pub fn fold(&mut self, range: impl RangeBounds<usize>) -> T {
94 let (start, end) = range_bounds_to_range(range, 0, self.original_size);
95 self._fold(1, 0, self.hsize, start, end)
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use my_testtools::*;
103 use rand::Rng;
104 use std::ops::Range;
105
106 #[test]
107 fn test() {
108 #![allow(clippy::needless_range_loop)]
109 let mut rng = rand::thread_rng();
110 let n = 100;
111
112 let mut seg = SegtreeLinearAddRangeSum::<i64>::new(n);
113 let mut vec = vec![0; n];
114
115 for _ in 0..300 {
116 let Range { start: l, end: r } = rand_range(&mut rng, 0..n);
117
118 let a = rng.gen_range(0..100);
119 let b = rng.gen_range(0..100);
120
121 seg.update(l..r, Linear { a, b });
122
123 for i in l..r {
124 vec[i] += a * i as i64 + b;
125 }
126
127 let Range { start: l, end: r } = rand_range(&mut rng, 0..n);
128
129 let res = seg.fold(l..r);
130 let ans = vec[l..r].iter().sum::<i64>();
131
132 assert_eq!(res, ans);
133 }
134 }
135}