ecnerwala's competitive programming library
// competitive-verifier: PROBLEM https://judge.yosupo.jp/problem/range_affine_range_sum
#include <bits/stdc++.h>
#include <cassert>
#include "seg_tree.hpp"
#include "modnum.hpp"
int main() {
std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr);
using num = modnum<998244353>;
int N, Q; std::cin >> N >> Q;
std::vector<num> A(N); for (auto& a : A) std::cin >> a;
struct linear_fn {
std::array<num, 2> v;
};
auto apply = [&](linear_fn a, linear_fn b) -> linear_fn {
return {a.v[0] + a.v[1] * b.v[0], a.v[1] * b.v[1]};
};
struct seg_node {
linear_fn lazy;
num tot;
num cnt;
};
seg_tree::in_order_layout layout(N);
std::vector<seg_node> seg(2*layout.N);
auto apply_lazy = [&](seg_tree::point a, linear_fn f) -> void {
seg[a].lazy = apply(f, seg[a].lazy);
seg[a].tot = seg[a].tot * f.v[1] + seg[a].cnt * f.v[0];
};
auto downdate_node = [&](seg_tree::point a) -> void {
apply_lazy(a.c(0), seg[a].lazy);
apply_lazy(a.c(1), seg[a].lazy);
seg[a].lazy = {num(0), num(1)};
};
auto update_node = [&](seg_tree::point a) -> void {
seg[a].tot = seg[a.c(0)].tot + seg[a.c(1)].tot;
seg[a].cnt = seg[a.c(0)].cnt + seg[a.c(1)].cnt;
};
for (int i = 0; i < N; i++) {
auto a = layout.get_point(i);
seg[a].lazy = {0, 1};
seg[a].tot = A[i];
seg[a].cnt = 1;
}
for (seg_tree::point a(N-1); a > 0; a--) {
seg[a].lazy = {0, 1};
update_node(a);
}
for (int q = 0; q < Q; q++) {
int op; std::cin >> op;
if (op == 0) {
int l, r; std::cin >> l >> r;
linear_fn f; std::cin >> f.v[1] >> f.v[0];
auto rng = layout.get_range(l, r);
rng.for_parents_down(downdate_node);
rng.for_each([&](seg_tree::point a) -> void {
apply_lazy(a, f);
});
rng.for_parents_up(update_node);
} else if (op == 1) {
int l, r; std::cin >> l >> r;
auto rng = layout.get_range(l, r);
rng.for_parents_down(downdate_node);
num ans = 0;
rng.for_each([&](seg_tree::point a) -> void {
ans += seg[a].tot;
});
std::cout << ans << '\n';
} else assert(false);
}
return 0;
}
#include <bits/stdc++.h>
#line 1 "verify/range_affine_range_sum.test.cpp"
// competitive-verifier: PROBLEM https://judge.yosupo.jp/problem/range_affine_range_sum
#line 5 "verify/range_affine_range_sum.test.cpp"
#line 4 "src/seg_tree.hpp"
namespace seg_tree {
// Floor of log_2(a); index of highest 1-bit
inline int floor_log_2(int a) {
return a ? (8 * sizeof(a)) - 1 - __builtin_clz(a) : -1;
}
inline int ceil_log_2(int a) {
return a ? floor_log_2(2*a-1) : -1;
}
inline int next_pow_2(int a) {
return 1 << ceil_log_2(a);
}
struct point {
int a;
point() : a(0) {}
explicit point(int a_) : a(a_) { assert(a >= -1); }
explicit operator bool () { return bool(a); }
// This is useful so you can directly do array indices
/* implicit */ operator int() const { return a; }
point c(bool z) const {
return point((a<<1)|z);
}
point operator [] (bool z) const {
return c(z);
}
point p() const {
return point(a>>1);
}
friend std::ostream& operator << (std::ostream& o, const point& p) { return o << int(p); }
template <typename F> void for_each(F f) const {
for (int v = a; v > 0; v >>= 1) {
f(point(v));
}
}
template <typename F> void for_each_down(F f) const {
// strictly greater than 0
for (int L = floor_log_2(a); L >= 0; L--) {
f(point(a >> L));
}
}
template <typename F> void for_each_up(F f) const {
for (int v = a; v > 0; v >>= 1) {
f(point(v));
}
}
template <typename F> void for_parents_down(F f) const {
// strictly greater than 0
for (int L = floor_log_2(a); L > 0; L--) {
f(point(a >> L));
}
}
template <typename F> void for_parents_up(F f) const {
for (int v = a >> 1; v > 0; v >>= 1) {
f(point(v));
}
}
point& operator ++ () { ++a; return *this; }
point operator ++ (int) { return point(a++); }
point& operator -- () { --a; return *this; }
point operator -- (int) { return point(a--); }
};
struct range {
int a, b;
range() : a(1), b(1) {}
range(int a_, int b_) : a(a_), b(b_) {
assert(1 <= a && a <= b && b <= 2 * a);
}
explicit range(std::array<int, 2> r) : range(r[0], r[1]) {}
explicit operator std::array<int, 2>() const {
return {a,b};
}
const int& operator[] (bool z) const {
return z ? b : a;
}
friend std::ostream& operator << (std::ostream& o, const range& r) { return o << "[" << r.a << ".." << r.b << ")"; }
// Iterate over the range from outside-in.
// Calls f(point a)
template <typename F> void for_each(F f) const {
for (int x = a, y = b; x < y; x >>= 1, y >>= 1) {
if (x & 1) f(point(x++));
if (y & 1) f(point(--y));
}
}
// Iterate over the range from outside-in.
// Calls f(point a, bool is_right)
template <typename F> void for_each_with_side(F f) const {
for (int x = a, y = b; x < y; x >>= 1, y >>= 1) {
if (x & 1) f(point(x++), false);
if (y & 1) f(point(--y), true);
}
}
// Iterate over the range from left to right.
// Calls f(point)
template <typename F> void for_each_l_to_r(F f) const {
int anc_depth = floor_log_2((a-1) ^ b);
int anc_msk = (1 << anc_depth) - 1;
for (int v = (-a) & anc_msk; v; v &= v-1) {
int i = __builtin_ctz(v);
f(point(((a-1) >> i) + 1));
}
for (int v = b & anc_msk; v; ) {
int i = floor_log_2(v);
f(point((b >> i) - 1));
v ^= (1 << i);
}
}
// Iterate over the range from right to left.
// Calls f(point)
template <typename F> void for_each_r_to_l(F f) const {
int anc_depth = floor_log_2((a-1) ^ b);
int anc_msk = (1 << anc_depth) - 1;
for (int v = b & anc_msk; v; v &= v-1) {
int i = __builtin_ctz(v);
f(point((b >> i) - 1));
}
for (int v = (-a) & anc_msk; v; ) {
int i = floor_log_2(v);
f(point(((a-1) >> i) + 1));
v ^= (1 << i);
}
}
template <typename F> void for_parents_down(F f) const {
int x = a, y = b;
if ((x ^ y) > x) { x <<= 1, std::swap(x, y); }
int dx = __builtin_ctz(x);
int dy = __builtin_ctz(y);
int anc_depth = floor_log_2((x-1) ^ y);
for (int i = floor_log_2(x); i > dx; i--) {
f(point(x >> i));
}
for (int i = anc_depth; i > dy; i--) {
f(point(y >> i));
}
}
template <typename F> void for_parents_up(F f) const {
int x = a, y = b;
if ((x ^ y) > x) { x <<= 1, std::swap(x, y); }
int dx = __builtin_ctz(x);
int dy = __builtin_ctz(y);
int anc_depth = floor_log_2((x-1) ^ y);
for (int i = dx+1; i <= anc_depth; i++) {
f(point(x >> i));
}
for (int v = y >> (dy+1); v; v >>= 1) {
f(point(v));
}
}
};
struct in_order_layout {
// Alias them in for convenience
using point = seg_tree::point;
using range = seg_tree::range;
int N, S;
in_order_layout() : N(0), S(0) {}
in_order_layout(int N_) : N(N_), S(N ? next_pow_2(N) : 0) {}
point get_point(int a) const {
assert(0 <= a && a < N);
a += S;
return point(a >= 2 * N ? a - N : a);
}
range get_range(int a, int b) const {
assert(0 <= a && a <= b && b <= N);
if (N == 0) return range();
a += S, b += S;
return range((a >= 2 * N ? 2*(a-N) : a), (b >= 2 * N ? 2*(b-N) : b));
}
range get_range(std::array<int, 2> p) const {
return get_range(p[0], p[1]);
}
int get_leaf_index(point pt) const {
int a = int(pt);
assert(N <= a && a < 2 * N);
return (a < S ? a + N : a) - S;
}
std::array<int, 2> get_node_bounds(point pt) const {
int a = int(pt);
assert(1 <= a && a < 2 * N);
int l = __builtin_clz(a) - __builtin_clz(2*N-1);
int x = a << l, y = (a+1) << l;
assert(S <= x && x < y && y <= 2*S);
return {(x >= 2 * N ? (x>>1) + N : x) - S, (y >= 2 * N ? (y>>1) + N : y) - S};
}
int get_node_split(point pt) const {
int a = int(pt);
assert(1 <= a && a < N);
int l = __builtin_clz(2*a+1) - __builtin_clz(2*N-1);
int x = (2*a+1) << l;
assert(S <= x && x < 2*S);
return (x >= 2 * N ? (x>>1) + N : x) - S;
}
int get_node_size(point pt) const {
auto bounds = get_node_bounds(pt);
return bounds[1] - bounds[0];
}
};
struct circular_layout {
// Alias them in for convenience
using point = seg_tree::point;
using range = seg_tree::range;
int N;
circular_layout() : N(0) {}
circular_layout(int N_) : N(N_) {}
point get_point(int a) const {
assert(0 <= a && a < N);
return point(N + a);
}
range get_range(int a, int b) const {
assert(0 <= a && a <= b && b <= N);
if (N == 0) return range();
return range(N + a, N + b);
}
range get_range(std::array<int, 2> p) const {
return get_range(p[0], p[1]);
}
int get_leaf_index(point pt) const {
int a = int(pt);
assert(N <= a && a < 2 * N);
return a - N;
}
// Returns {x,y} so that 0 <= x < N and 1 <= y <= N
// If the point is non-wrapping, then 0 <= x < y <= N
std::array<int, 2> get_node_bounds(point pt) const {
int a = int(pt);
assert(1 <= a && a < 2 * N);
int l = __builtin_clz(a) - __builtin_clz(2*N-1);
int S = next_pow_2(N);
int x = a << l, y = (a+1) << l;
assert(S <= x && x < y && y <= 2*S);
return {(x >= 2 * N ? x >> 1 : x) - N, (y > 2 * N ? y >> 1 : y) - N};
}
// Returns the split point of the node, such that 1 <= s <= N.
int get_node_split(point pt) const {
int a = int(pt);
assert(1 <= a && a < N);
return get_node_bounds(pt.c(0))[1];
}
int get_node_size(point pt) const {
auto bounds = get_node_bounds(pt);
int r = bounds[1] - bounds[0];
return r > 0 ? r : r + N;
}
};
} // namespace seg_tree
#line 2 "src/modnum.hpp"
#line 9 "src/modnum.hpp"
template <typename T> T mod_inv_in_range(T a, T m) {
// assert(0 <= a && a < m);
T x = a, y = m;
// abs coeff of a in x and y (they're always opposite sign)
T vx = 1, vy = 0;
bool swap = false;
while (x) {
T k = y / x;
y %= x;
vy += k * vx;
std::swap(x, y);
std::swap(vx, vy);
swap ^= 1;
}
assert(y == 1);
return swap ? vy : m - vy;
}
template <typename T> struct extended_gcd_result {
T gcd;
T coeff_a, coeff_b;
};
template <typename T> extended_gcd_result<T> extended_gcd(T a, T b) {
T x = a, y = b;
// coeff of a and b in x and y
T ax = 1, ay = 0;
T bx = 0, by = 1;
while (x) {
T k = y / x;
y %= x;
ay -= k * ax;
by -= k * bx;
std::swap(x, y);
std::swap(ax, ay);
std::swap(bx, by);
}
return {y, ay, by};
}
template <typename T> T mod_inv(T a, T m) {
a %= m;
a = a < 0 ? a + m : a;
return mod_inv_in_range(a, m);
}
// Derives the boilerplate operator surface of a number type from its compound
// ops, ==, neg(), and inv().
// Bodies are only instantiated on use, so a type may omit some of the
// underlying pieces if the corresponding derived ops are never called.
template <typename Self>
struct num_ops {
Self operator+ () const { return static_cast<const Self&>(*this); }
Self operator- () const { return static_cast<const Self&>(*this).neg(); }
friend Self operator ++ (Self& a, int) { Self r = a; ++a; return r; }
friend Self operator -- (Self& a, int) { Self r = a; --a; return r; }
friend Self operator + (const Self& a, const Self& b) { return Self(a) += b; }
friend Self operator - (const Self& a, const Self& b) { return Self(a) -= b; }
friend Self operator * (const Self& a, const Self& b) { return Self(a) *= b; }
friend Self operator / (const Self& a, const Self& b) { return Self(a) /= b; }
friend bool operator != (const Self& a, const Self& b) { return !(a == b); }
friend Self neg(const Self& a) { return a.neg(); }
friend Self inv(const Self& a) { return a.inv(); }
};
// Storage and arithmetic for numbers mod Self::MOD, as a reduced
// representative v in [0, MOD) of unsigned type V.
// The type provides static MOD (of type V), reduce (value -> representative),
// and *=;
// everything else is derived here, valid for any MOD up to V's full range
// (sums and differences are tracked mod 2^bits, so no headroom is needed).
// Hooks may be overridden in the type's own body (e.g. a faster += / -=).
template <typename Self, typename V>
struct mod_ops : num_ops<Self> {
static_assert(std::unsigned_integral<V>);
V v;
struct is_reduced_tag {};
mod_ops() : v(0) {}
mod_ops(V v_, is_reduced_tag) : v(v_) { assert(v < Self::MOD); }
template <std::integral I> mod_ops(I x) : v(Self::reduce(x)) {}
static Self from_reduced(V v) { return Self(v, is_reduced_tag{}); }
// A negative value reduces via its nonnegative complement: x = -1 - ~x.
static V reduce(std::signed_integral auto x) {
using U = std::make_unsigned_t<decltype(x)>;
return x < 0 ? V(Self::MOD - 1 - Self::reduce(U(~x))) : Self::reduce(U(x));
}
explicit operator V() const { return v; }
std::make_signed_t<V> balanced() const {
return std::make_signed_t<V>(Self::MOD-v > v ? v : v - Self::MOD);
}
friend bool operator == (const Self& a, const Self& b) { return a.v == b.v; }
friend std::ostream& operator << (std::ostream& out, const Self& n) { return out << n.v; }
friend std::istream& operator >> (std::istream& in, Self& n) { int64_t v_; in >> v_; n = Self(v_); return in; }
Self& operator ++ () {
++v;
if (v == Self::MOD) v = 0;
return self();
}
Self& operator -- () {
if (v == 0) v = Self::MOD;
--v;
return self();
}
Self& operator += (const Self& o) { v = Self::sub_mod_raw(v, Self::MOD - o.v); return self(); }
Self& operator -= (const Self& o) { v = Self::sub_mod_raw(v, o.v); return self(); }
Self& operator /= (const Self& o) { return self() *= o.inv(); }
// Returns a - b mod MOD, for b in [0, MOD]; wraparound detects the underflow.
static V sub_mod_raw(V a, V b) { return a < b ? a - b + Self::MOD : a - b; }
Self neg() const { return from_reduced(v ? Self::MOD - v : 0); }
Self inv() const { return from_reduced(mod_inv_in_range(v, Self::MOD)); }
private:
Self& self() { return static_cast<Self&>(*this); }
};
template <auto MOD_> struct modnum : mod_ops<modnum<MOD_>, std::make_unsigned_t<decltype(MOD_)>> {
using Self = modnum;
static_assert(MOD_ > 0, "MOD must be positive");
using V = std::make_unsigned_t<decltype(MOD_)>;
static constexpr V MOD = V(MOD_);
using base = mod_ops<modnum, V>;
using base::base;
using base::v;
using base::reduce;
static V reduce(std::unsigned_integral auto x) { return V(x % MOD); }
explicit operator std::make_signed_t<V>() const
requires (MOD <= V(std::numeric_limits<std::make_signed_t<V>>::max()))
{
return std::make_signed_t<V>(v);
}
Self& operator *= (const Self& o) {
if constexpr (sizeof(V) <= 4) v = V(uint64_t(v) * o.v % MOD);
else v = V(__uint128_t(v) * o.v % MOD);
return *this;
}
};
struct mod_goldilocks : mod_ops<mod_goldilocks, uint64_t> {
using Self = mod_goldilocks;
static constexpr uint64_t MOD = 0xffffffff00000001ull;
static constexpr uint64_t EPS = -MOD;
// We have 2^32 is a primitive 6th root of unity.
// Note that omega_8 + omega_8^7 == 2^24 - 2^72 == sqrt(2)
// We'll pick the root so that 2^24 - 2^72 is our primitive 384th root of unity.
static constexpr uint64_t PRIMITIVE_ROOT = 2717;
using base = mod_ops<mod_goldilocks, uint64_t>;
using base::base;
using base::reduce;
mod_goldilocks() = default;
mod_goldilocks(__int128_t a) : base(a < 0 ? uint64_t(MOD - 1 - __uint128_t(~a) % MOD) : uint64_t(__uint128_t(a) % MOD), is_reduced_tag{}) {}
mod_goldilocks(__uint128_t a) : base(uint64_t(a % MOD), is_reduced_tag{}) {}
// Avoids the division: any uint64_t is within MOD of reduced.
static uint64_t reduce(std::unsigned_integral auto x) {
static_assert(sizeof(x) <= 8);
uint64_t a = x;
return a >= MOD ? a - MOD : a;
}
// returns a-b, assuming -MOD <= a-b, e.g. b <= MOD
static uint64_t sub_mod_raw(uint64_t a, uint64_t b) {
#if defined(__x86_64__)
// TODO: We could try to write this using intrinsics, but GCC sometimes produces the wrong code.
uint64_t res_wrapped = a;
uint64_t adjustment = b;
asm (
// AT&T syntax: SRC DST
"sub %[y], %[x]\n\t"
// Trick from plonky2 implementation:
// After sub, flag CF is set iff we underflowed. We want to correct by EPS == 2^32 - 1 iff C is set.
// sbb (subtract with borrow) computes DST <- DST - SRC - CF
// Thus, we can use the 32-bit form of sbb on a dummy register to load CF ? EPS : 0.
// Here, we'll just reuse the original register holding b.
"sbb %k[y], %k[y]\n\t"
: [x] "+r"(res_wrapped),
[y] "+r"(adjustment)
:
: "cc"
);
#else
uint64_t res_wrapped = a - b;
uint64_t adjustment = (res_wrapped > a) ? EPS : 0;
#endif
return res_wrapped - adjustment;
}
// Reduce lo + 2^64 * mi + 2^96 * hi, where hi <= MOD
static uint64_t reduce_u160_raw(uint64_t lo, uint32_t mi, uint64_t hi) {
// result = lo - hi + EPS * mi
// 0 <= lo <= 2^64 - 1 = MOD + EPS - 1
// 0 <= EPS * mi <= (2^32 - 1) * EPS = MOD - 1 - EPS
// 0 <= hi <= MOD
// -MOD <= lo - hi + EPS * mi <= 2*MOD-2
// so we do have some leeway
return sub_mod_raw(sub_mod_raw(lo, hi), MOD-(uint64_t(mi)<<32)+mi);
}
static uint64_t reduce_u128_raw(__uint128_t v) {
uint64_t hi = uint64_t(v >> 64);
uint64_t lo = uint64_t(v);
uint32_t hi_hi = uint32_t(hi >> 32);
uint32_t hi_lo = uint32_t(hi);
return reduce_u160_raw(lo, hi_lo, hi_hi);
}
Self& operator *= (Self o) {
v = reduce_u128_raw(__uint128_t(v) * __uint128_t(o.v));
return *this;
}
};
template <typename T> T power(T a, long long b) {
assert(b >= 0);
T r = 1; while (b) { if (b & 1) r *= a; b >>= 1; a *= a; } return r;
}
template <typename U, typename V> struct pairnum : num_ops<pairnum<U, V>> {
using Self = pairnum;
U u;
V v;
pairnum() : u(0), v(0) {}
pairnum(long long val) : u(val), v(val) {}
pairnum(const U& u_, const V& v_) : u(u_), v(v_) {}
friend std::ostream& operator << (std::ostream& out, const Self& n) { return out << '(' << n.u << ',' << ' ' << n.v << ')'; }
friend std::istream& operator >> (std::istream& in, Self& n) { long long val; in >> val; n = Self(val); return in; }
friend bool operator == (const Self& a, const Self& b) { return a.u == b.u && a.v == b.v; }
Self inv() const {
return Self(u.inv(), v.inv());
}
Self neg() const {
return Self(u.neg(), v.neg());
}
Self& operator ++ () {
++u, ++v;
return *this;
}
Self& operator -- () {
--u, --v;
return *this;
}
Self& operator += (const Self& o) {
u += o.u;
v += o.v;
return *this;
}
Self& operator -= (const Self& o) {
u -= o.u;
v -= o.v;
return *this;
}
Self& operator *= (const Self& o) {
u *= o.u;
v *= o.v;
return *this;
}
Self& operator /= (const Self& o) {
u /= o.u;
v /= o.v;
return *this;
}
};
template <typename tag> struct dynamic_modnum : mod_ops<dynamic_modnum<tag>, uint32_t> {
using Self = dynamic_modnum;
private:
inline static uint32_t MOD_ = 0;
inline static uint64_t BARRETT_M = 0;
public:
// Make only the const-reference public, to force the use of set_mod
static constexpr uint32_t const& MOD = MOD_;
using base = mod_ops<dynamic_modnum, uint32_t>;
using base::base;
using base::v;
using base::reduce;
// Barret reduction taken from KACTL:
/**
* Author: Simon Lindholm
* Date: 2020-05-30
* License: CC0
* Source: https://en.wikipedia.org/wiki/Barrett_reduction
* Description: Compute $a \% b$ about 5 times faster than usual, where $b$ is constant but not known at compile time.
* Returns a value congruent to $a \pmod b$ in the range $[0, 2b)$.
* Status: proven correct, stress-tested
* Measured as having 4 times lower latency, and 8 times higher throughput, see stress-test.
* Details:
* More precisely, it can be proven that the result equals 0 only if $a = 0$,
* and otherwise lies in $[1, (1 + a/2^64) * b)$.
*/
static void set_mod(int mod) {
assert(mod > 0);
MOD_ = uint32_t(mod);
BARRETT_M = (uint64_t(-1) / MOD);
}
static uint32_t barrett_reduce_partial(uint64_t a) {
return uint32_t(a - uint64_t((__uint128_t(BARRETT_M) * a) >> 64) * MOD);
}
static uint32_t barrett_reduce(uint64_t a) {
int32_t res = int32_t(barrett_reduce_partial(a) - MOD);
return uint32_t((res < 0) ? res + int32_t(MOD) : res);
}
struct mod_reader {
friend std::istream& operator >> (std::istream& i, mod_reader) {
int mod; i >> mod;
Self::set_mod(mod);
return i;
}
};
static mod_reader MOD_READER() {
return mod_reader();
}
static uint32_t reduce(std::unsigned_integral auto x) {
static_assert(sizeof(x) <= 8);
return barrett_reduce(x);
}
explicit operator int() const { return int(v); }
Self& operator *= (const Self& o) {
v = barrett_reduce(uint64_t(v) * o.v);
return *this;
}
};
template <typename T> struct mod_constraint {
T v, mod;
friend mod_constraint operator & (mod_constraint a, mod_constraint b) {
if (a.mod < b.mod) std::swap(a, b);
if (b.mod == 1) return a;
extended_gcd_result<T> egcd = extended_gcd<T>(a.mod, b.mod);
assert(a.v % egcd.gcd == b.v % egcd.gcd);
T extra = b.v - a.v % b.mod;
extra /= egcd.gcd;
extra *= egcd.coeff_a;
extra %= b.mod / egcd.gcd;
extra += (extra < 0) ? b.mod / egcd.gcd : 0;
return mod_constraint{
a.v + extra * a.mod,
a.mod * (b.mod / egcd.gcd)
};
}
};
#line 8 "verify/range_affine_range_sum.test.cpp"
int main() {
std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr);
using num = modnum<998244353>;
int N, Q; std::cin >> N >> Q;
std::vector<num> A(N); for (auto& a : A) std::cin >> a;
struct linear_fn {
std::array<num, 2> v;
};
auto apply = [&](linear_fn a, linear_fn b) -> linear_fn {
return {a.v[0] + a.v[1] * b.v[0], a.v[1] * b.v[1]};
};
struct seg_node {
linear_fn lazy;
num tot;
num cnt;
};
seg_tree::in_order_layout layout(N);
std::vector<seg_node> seg(2*layout.N);
auto apply_lazy = [&](seg_tree::point a, linear_fn f) -> void {
seg[a].lazy = apply(f, seg[a].lazy);
seg[a].tot = seg[a].tot * f.v[1] + seg[a].cnt * f.v[0];
};
auto downdate_node = [&](seg_tree::point a) -> void {
apply_lazy(a.c(0), seg[a].lazy);
apply_lazy(a.c(1), seg[a].lazy);
seg[a].lazy = {num(0), num(1)};
};
auto update_node = [&](seg_tree::point a) -> void {
seg[a].tot = seg[a.c(0)].tot + seg[a.c(1)].tot;
seg[a].cnt = seg[a.c(0)].cnt + seg[a.c(1)].cnt;
};
for (int i = 0; i < N; i++) {
auto a = layout.get_point(i);
seg[a].lazy = {0, 1};
seg[a].tot = A[i];
seg[a].cnt = 1;
}
for (seg_tree::point a(N-1); a > 0; a--) {
seg[a].lazy = {0, 1};
update_node(a);
}
for (int q = 0; q < Q; q++) {
int op; std::cin >> op;
if (op == 0) {
int l, r; std::cin >> l >> r;
linear_fn f; std::cin >> f.v[1] >> f.v[0];
auto rng = layout.get_range(l, r);
rng.for_parents_down(downdate_node);
rng.for_each([&](seg_tree::point a) -> void {
apply_lazy(a, f);
});
rng.for_parents_up(update_node);
} else if (op == 1) {
int l, r; std::cin >> l >> r;
auto rng = layout.get_range(l, r);
rng.for_parents_down(downdate_node);
num ans = 0;
rng.for_each([&](seg_tree::point a) -> void {
ans += seg[a].tot;
});
std::cout << ans << '\n';
} else assert(false);
}
return 0;
}
// clang-format off
// @formatter:off
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wunknown-warning-option"
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#pragma GCC diagnostic ignored "-Wmultistatement-macros"
#include <bits/stdc++.h>
// src/seg_tree.hpp
namespace seg_tree{
inline int floor_log_2(int a){
return a?(8*sizeof(a))-1-__builtin_clz(a):-1;
}
inline int ceil_log_2(int a){
return a?floor_log_2(2*a-1):-1;
}
inline int next_pow_2(int a){
return 1<<ceil_log_2(a);
}
struct point{
int a;
point():a(0){}
explicit point(int a_):a(a_){assert(a>=-1);}
explicit operator bool(){return bool(a);}
operator int()const{return a;}
point c(bool z)const{
return point((a<<1)|z);
}
point operator[](bool z)const{
return c(z);
}
point p()const{
return point(a>>1);
}
friend std::ostream&operator<<(std::ostream&o,const point&p){return o<<int(p);}
template<typename F>void for_each(F f)const{
for(int v=a;v>0;v>>=1){
f(point(v));
}
}
template<typename F>void for_each_down(F f)const{
for(int L=floor_log_2(a);L>=0;L--){
f(point(a>>L));
}
}
template<typename F>void for_each_up(F f)const{
for(int v=a;v>0;v>>=1){
f(point(v));
}
}
template<typename F>void for_parents_down(F f)const{
for(int L=floor_log_2(a);L>0;L--){
f(point(a>>L));
}
}
template<typename F>void for_parents_up(F f)const{
for(int v=a>>1;v>0;v>>=1){
f(point(v));
}
}
point&operator++(){++a;return*this;}
point operator++(int){return point(a++);}
point&operator--(){--a;return*this;}
point operator--(int){return point(a--);}
};
struct range{
int a,b;
range():a(1),b(1){}
range(int a_,int b_):a(a_),b(b_){
assert(1<=a&&a<=b&&b<=2*a);
}
explicit range(std::array<int,2>r):range(r[0],r[1]){}
explicit operator std::array<int,2>()const{
return{a,b};
}
const int&operator[](bool z)const{
return z?b:a;
}
friend std::ostream&operator<<(std::ostream&o,const range&r){return o<<"["<<r.a<<".."<<r.b<<")";}
template<typename F>void for_each(F f)const{
for(int x=a,y=b;x<y;x>>=1,y>>=1){
if(x&1)f(point(x++));
if(y&1)f(point(--y));
}
}
template<typename F>void for_each_with_side(F f)const{
for(int x=a,y=b;x<y;x>>=1,y>>=1){
if(x&1)f(point(x++),false);
if(y&1)f(point(--y),true);
}
}
template<typename F>void for_each_l_to_r(F f)const{
int anc_depth=floor_log_2((a-1)^b);
int anc_msk=(1<<anc_depth)-1;
for(int v=(-a)&anc_msk;v;v&=v-1){
int i=__builtin_ctz(v);
f(point(((a-1)>>i)+1));
}
for(int v=b&anc_msk;v;){
int i=floor_log_2(v);
f(point((b>>i)-1));
v^=(1<<i);
}
}
template<typename F>void for_each_r_to_l(F f)const{
int anc_depth=floor_log_2((a-1)^b);
int anc_msk=(1<<anc_depth)-1;
for(int v=b&anc_msk;v;v&=v-1){
int i=__builtin_ctz(v);
f(point((b>>i)-1));
}
for(int v=(-a)&anc_msk;v;){
int i=floor_log_2(v);
f(point(((a-1)>>i)+1));
v^=(1<<i);
}
}
template<typename F>void for_parents_down(F f)const{
int x=a,y=b;
if((x^y)>x){x<<=1,std::swap(x,y);}
int dx=__builtin_ctz(x);
int dy=__builtin_ctz(y);
int anc_depth=floor_log_2((x-1)^y);
for(int i=floor_log_2(x);i>dx;i--){
f(point(x>>i));
}
for(int i=anc_depth;i>dy;i--){
f(point(y>>i));
}
}
template<typename F>void for_parents_up(F f)const{
int x=a,y=b;
if((x^y)>x){x<<=1,std::swap(x,y);}
int dx=__builtin_ctz(x);
int dy=__builtin_ctz(y);
int anc_depth=floor_log_2((x-1)^y);
for(int i=dx+1;i<=anc_depth;i++){
f(point(x>>i));
}
for(int v=y>>(dy+1);v;v>>=1){
f(point(v));
}
}
};
struct in_order_layout{
using point=seg_tree::point;
using range=seg_tree::range;
int N,S;
in_order_layout():N(0),S(0){}
in_order_layout(int N_):N(N_),S(N?next_pow_2(N):0){}
point get_point(int a)const{
assert(0<=a&&a<N);
a+=S;
return point(a>=2*N?a-N:a);
}
range get_range(int a,int b)const{
assert(0<=a&&a<=b&&b<=N);
if(N==0)return range();
a+=S,b+=S;
return range((a>=2*N?2*(a-N):a),(b>=2*N?2*(b-N):b));
}
range get_range(std::array<int,2>p)const{
return get_range(p[0],p[1]);
}
int get_leaf_index(point pt)const{
int a=int(pt);
assert(N<=a&&a<2*N);
return(a<S?a+N:a)-S;
}
std::array<int,2>get_node_bounds(point pt)const{
int a=int(pt);
assert(1<=a&&a<2*N);
int l=__builtin_clz(a)-__builtin_clz(2*N-1);
int x=a<<l,y=(a+1)<<l;
assert(S<=x&&x<y&&y<=2*S);
return{(x>=2*N?(x>>1)+N:x)-S,(y>=2*N?(y>>1)+N:y)-S};
}
int get_node_split(point pt)const{
int a=int(pt);
assert(1<=a&&a<N);
int l=__builtin_clz(2*a+1)-__builtin_clz(2*N-1);
int x=(2*a+1)<<l;
assert(S<=x&&x<2*S);
return(x>=2*N?(x>>1)+N:x)-S;
}
int get_node_size(point pt)const{
auto bounds=get_node_bounds(pt);
return bounds[1]-bounds[0];
}
};
struct circular_layout{
using point=seg_tree::point;
using range=seg_tree::range;
int N;
circular_layout():N(0){}
circular_layout(int N_):N(N_){}
point get_point(int a)const{
assert(0<=a&&a<N);
return point(N+a);
}
range get_range(int a,int b)const{
assert(0<=a&&a<=b&&b<=N);
if(N==0)return range();
return range(N+a,N+b);
}
range get_range(std::array<int,2>p)const{
return get_range(p[0],p[1]);
}
int get_leaf_index(point pt)const{
int a=int(pt);
assert(N<=a&&a<2*N);
return a-N;
}
std::array<int,2>get_node_bounds(point pt)const{
int a=int(pt);
assert(1<=a&&a<2*N);
int l=__builtin_clz(a)-__builtin_clz(2*N-1);
int S=next_pow_2(N);
int x=a<<l,y=(a+1)<<l;
assert(S<=x&&x<y&&y<=2*S);
return{(x>=2*N?x>>1:x)-N,(y>2*N?y>>1:y)-N};
}
int get_node_split(point pt)const{
int a=int(pt);
assert(1<=a&&a<N);
return get_node_bounds(pt.c(0))[1];
}
int get_node_size(point pt)const{
auto bounds=get_node_bounds(pt);
int r=bounds[1]-bounds[0];
return r>0?r:r+N;
}
};
}
// src/modnum.hpp
template<typename T>T mod_inv_in_range(T a,T m){
T x=a,y=m;
T vx=1,vy=0;
bool swap=false;
while(x){
T k=y/x;
y%=x;
vy+=k*vx;
std::swap(x,y);
std::swap(vx,vy);
swap^=1;
}
assert(y==1);
return swap?vy:m-vy;
}
template<typename T>struct extended_gcd_result{
T gcd;
T coeff_a,coeff_b;
};
template<typename T>extended_gcd_result<T>extended_gcd(T a,T b){
T x=a,y=b;
T ax=1,ay=0;
T bx=0,by=1;
while(x){
T k=y/x;
y%=x;
ay-=k*ax;
by-=k*bx;
std::swap(x,y);
std::swap(ax,ay);
std::swap(bx,by);
}
return{y,ay,by};
}
template<typename T>T mod_inv(T a,T m){
a%=m;
a=a<0?a+m:a;
return mod_inv_in_range(a,m);
}
template<typename Self>
struct num_ops{
Self operator+()const{return static_cast<const Self&>(*this);}
Self operator-()const{return static_cast<const Self&>(*this).neg();}
friend Self operator++(Self&a,int){Self r=a;++a;return r;}
friend Self operator--(Self&a,int){Self r=a;--a;return r;}
friend Self operator+(const Self&a,const Self&b){return Self(a)+=b;}
friend Self operator-(const Self&a,const Self&b){return Self(a)-=b;}
friend Self operator*(const Self&a,const Self&b){return Self(a)*=b;}
friend Self operator/(const Self&a,const Self&b){return Self(a)/=b;}
friend bool operator!=(const Self&a,const Self&b){return!(a==b);}
friend Self neg(const Self&a){return a.neg();}
friend Self inv(const Self&a){return a.inv();}
};
template<typename Self,typename V>
struct mod_ops:num_ops<Self>{
static_assert(std::unsigned_integral<V>);
V v;
struct is_reduced_tag{};
mod_ops():v(0){}
mod_ops(V v_,is_reduced_tag):v(v_){assert(v<Self::MOD);}
template<std::integral I>mod_ops(I x):v(Self::reduce(x)){}
static Self from_reduced(V v){return Self(v,is_reduced_tag{});}
static V reduce(std::signed_integral auto x){
using U=std::make_unsigned_t<decltype(x)>;
return x<0?V(Self::MOD-1-Self::reduce(U(~x))):Self::reduce(U(x));
}
explicit operator V()const{return v;}
std::make_signed_t<V>balanced()const{
return std::make_signed_t<V>(Self::MOD-v>v?v:v-Self::MOD);
}
friend bool operator==(const Self&a,const Self&b){return a.v==b.v;}
friend std::ostream&operator<<(std::ostream&out,const Self&n){return out<<n.v;}
friend std::istream&operator>>(std::istream&in,Self&n){int64_t v_;in>>v_;n=Self(v_);return in;}
Self&operator++(){
++v;
if(v==Self::MOD)v=0;
return self();
}
Self&operator--(){
if(v==0)v=Self::MOD;
--v;
return self();
}
Self&operator+=(const Self&o){v=Self::sub_mod_raw(v,Self::MOD-o.v);return self();}
Self&operator-=(const Self&o){v=Self::sub_mod_raw(v,o.v);return self();}
Self&operator/=(const Self&o){return self()*=o.inv();}
static V sub_mod_raw(V a,V b){return a<b?a-b+Self::MOD:a-b;}
Self neg()const{return from_reduced(v?Self::MOD-v:0);}
Self inv()const{return from_reduced(mod_inv_in_range(v,Self::MOD));}
private:
Self&self(){return static_cast<Self&>(*this);}
};
template<auto MOD_>struct modnum:mod_ops<modnum<MOD_>,std::make_unsigned_t<decltype(MOD_)>>{
using Self=modnum;
static_assert(MOD_>0,"MOD must be positive");
using V=std::make_unsigned_t<decltype(MOD_)>;
static constexpr V MOD=V(MOD_);
using base=mod_ops<modnum,V>;
using base::base;
using base::v;
using base::reduce;
static V reduce(std::unsigned_integral auto x){return V(x%MOD);}
explicit operator std::make_signed_t<V>()const
requires(MOD<=V(std::numeric_limits<std::make_signed_t<V>>::max()))
{
return std::make_signed_t<V>(v);
}
Self&operator*=(const Self&o){
if constexpr(sizeof(V)<=4)v=V(uint64_t(v)*o.v%MOD);
else v=V(__uint128_t(v)*o.v%MOD);
return*this;
}
};
struct mod_goldilocks:mod_ops<mod_goldilocks,uint64_t>{
using Self=mod_goldilocks;
static constexpr uint64_t MOD=0xffffffff00000001ull;
static constexpr uint64_t EPS=-MOD;
static constexpr uint64_t PRIMITIVE_ROOT=2717;
using base=mod_ops<mod_goldilocks,uint64_t>;
using base::base;
using base::reduce;
mod_goldilocks()=default;
mod_goldilocks(__int128_t a):base(a<0?uint64_t(MOD-1-__uint128_t(~a)%MOD):uint64_t(__uint128_t(a)%MOD),is_reduced_tag{}){}
mod_goldilocks(__uint128_t a):base(uint64_t(a%MOD),is_reduced_tag{}){}
static uint64_t reduce(std::unsigned_integral auto x){
static_assert(sizeof(x)<=8);
uint64_t a=x;
return a>=MOD?a-MOD:a;
}
static uint64_t sub_mod_raw(uint64_t a,uint64_t b){
#if defined(__x86_64__)
uint64_t res_wrapped=a;
uint64_t adjustment=b;
asm(
"sub %[y], %[x]\n\t"
"sbb %k[y], %k[y]\n\t"
:[x]"+r"(res_wrapped),
[y]"+r"(adjustment)
:
:"cc"
);
#else
uint64_t res_wrapped=a-b;
uint64_t adjustment=(res_wrapped>a)?EPS:0;
#endif
return res_wrapped-adjustment;
}
static uint64_t reduce_u160_raw(uint64_t lo,uint32_t mi,uint64_t hi){
return sub_mod_raw(sub_mod_raw(lo,hi),MOD-(uint64_t(mi)<<32)+mi);
}
static uint64_t reduce_u128_raw(__uint128_t v){
uint64_t hi=uint64_t(v>>64);
uint64_t lo=uint64_t(v);
uint32_t hi_hi=uint32_t(hi>>32);
uint32_t hi_lo=uint32_t(hi);
return reduce_u160_raw(lo,hi_lo,hi_hi);
}
Self&operator*=(Self o){
v=reduce_u128_raw(__uint128_t(v)*__uint128_t(o.v));
return*this;
}
};
template<typename T>T power(T a,long long b){
assert(b>=0);
T r=1;while(b){if(b&1)r*=a;b>>=1;a*=a;}return r;
}
template<typename U,typename V>struct pairnum:num_ops<pairnum<U,V>>{
using Self=pairnum;
U u;
V v;
pairnum():u(0),v(0){}
pairnum(long long val):u(val),v(val){}
pairnum(const U&u_,const V&v_):u(u_),v(v_){}
friend std::ostream&operator<<(std::ostream&out,const Self&n){return out<<'('<<n.u<<','<<' '<<n.v<<')';}
friend std::istream&operator>>(std::istream&in,Self&n){long long val;in>>val;n=Self(val);return in;}
friend bool operator==(const Self&a,const Self&b){return a.u==b.u&&a.v==b.v;}
Self inv()const{
return Self(u.inv(),v.inv());
}
Self neg()const{
return Self(u.neg(),v.neg());
}
Self&operator++(){
++u,++v;
return*this;
}
Self&operator--(){
--u,--v;
return*this;
}
Self&operator+=(const Self&o){
u+=o.u;
v+=o.v;
return*this;
}
Self&operator-=(const Self&o){
u-=o.u;
v-=o.v;
return*this;
}
Self&operator*=(const Self&o){
u*=o.u;
v*=o.v;
return*this;
}
Self&operator/=(const Self&o){
u/=o.u;
v/=o.v;
return*this;
}
};
template<typename tag>struct dynamic_modnum:mod_ops<dynamic_modnum<tag>,uint32_t>{
using Self=dynamic_modnum;
private:
inline static uint32_t MOD_=0;
inline static uint64_t BARRETT_M=0;
public:
static constexpr uint32_t const&MOD=MOD_;
using base=mod_ops<dynamic_modnum,uint32_t>;
using base::base;
using base::v;
using base::reduce;
static void set_mod(int mod){
assert(mod>0);
MOD_=uint32_t(mod);
BARRETT_M=(uint64_t(-1)/MOD);
}
static uint32_t barrett_reduce_partial(uint64_t a){
return uint32_t(a-uint64_t((__uint128_t(BARRETT_M)*a)>>64)*MOD);
}
static uint32_t barrett_reduce(uint64_t a){
int32_t res=int32_t(barrett_reduce_partial(a)-MOD);
return uint32_t((res<0)?res+int32_t(MOD):res);
}
struct mod_reader{
friend std::istream&operator>>(std::istream&i,mod_reader){
int mod;i>>mod;
Self::set_mod(mod);
return i;
}
};
static mod_reader MOD_READER(){
return mod_reader();
}
static uint32_t reduce(std::unsigned_integral auto x){
static_assert(sizeof(x)<=8);
return barrett_reduce(x);
}
explicit operator int()const{return int(v);}
Self&operator*=(const Self&o){
v=barrett_reduce(uint64_t(v)*o.v);
return*this;
}
};
template<typename T>struct mod_constraint{
T v,mod;
friend mod_constraint operator&(mod_constraint a,mod_constraint b){
if(a.mod<b.mod)std::swap(a,b);
if(b.mod==1)return a;
extended_gcd_result<T>egcd=extended_gcd<T>(a.mod,b.mod);
assert(a.v%egcd.gcd==b.v%egcd.gcd);
T extra=b.v-a.v%b.mod;
extra/=egcd.gcd;
extra*=egcd.coeff_a;
extra%=b.mod/egcd.gcd;
extra+=(extra<0)?b.mod/egcd.gcd:0;
return mod_constraint{
a.v+extra*a.mod,
a.mod*(b.mod/egcd.gcd)
};
}
};
// verify/range_affine_range_sum.test.cpp
int main(){
std::ios_base::sync_with_stdio(false);std::cin.tie(nullptr);
using num=modnum<998244353>;
int N,Q;std::cin>>N>>Q;
std::vector<num>A(N);for(auto&a:A)std::cin>>a;
struct linear_fn{
std::array<num,2>v;
};
auto apply=[&](linear_fn a,linear_fn b)->linear_fn{
return{a.v[0]+a.v[1]*b.v[0],a.v[1]*b.v[1]};
};
struct seg_node{
linear_fn lazy;
num tot;
num cnt;
};
seg_tree::in_order_layout layout(N);
std::vector<seg_node>seg(2*layout.N);
auto apply_lazy=[&](seg_tree::point a,linear_fn f)->void{
seg[a].lazy=apply(f,seg[a].lazy);
seg[a].tot=seg[a].tot*f.v[1]+seg[a].cnt*f.v[0];
};
auto downdate_node=[&](seg_tree::point a)->void{
apply_lazy(a.c(0),seg[a].lazy);
apply_lazy(a.c(1),seg[a].lazy);
seg[a].lazy={num(0),num(1)};
};
auto update_node=[&](seg_tree::point a)->void{
seg[a].tot=seg[a.c(0)].tot+seg[a.c(1)].tot;
seg[a].cnt=seg[a.c(0)].cnt+seg[a.c(1)].cnt;
};
for(int i=0;i<N;i++){
auto a=layout.get_point(i);
seg[a].lazy={0,1};
seg[a].tot=A[i];
seg[a].cnt=1;
}
for(seg_tree::point a(N-1);a>0;a--){
seg[a].lazy={0,1};
update_node(a);
}
for(int q=0;q<Q;q++){
int op;std::cin>>op;
if(op==0){
int l,r;std::cin>>l>>r;
linear_fn f;std::cin>>f.v[1]>>f.v[0];
auto rng=layout.get_range(l,r);
rng.for_parents_down(downdate_node);
rng.for_each([&](seg_tree::point a)->void{
apply_lazy(a,f);
});
rng.for_parents_up(update_node);
}else if(op==1){
int l,r;std::cin>>l>>r;
auto rng=layout.get_range(l,r);
rng.for_parents_down(downdate_node);
num ans=0;
rng.for_each([&](seg_tree::point a)->void{
ans+=seg[a].tot;
});
std::cout<<ans<<'\n';
}else assert(false);
}
return 0;
}
#pragma GCC diagnostic pop
// clang-format on
// @formatter:on
| Env | Name | Status | Elapsed | Memory |
|---|---|---|---|---|
| g++-sanitizer | example_00 |
|
16 ms | 8 MB |
| g++-sanitizer | max_random_00 |
|
4605 ms | 33 MB |
| g++-sanitizer | max_random_01 |
|
4649 ms | 33 MB |
| g++-sanitizer | max_random_02 |
|
4643 ms | 34 MB |
| g++-sanitizer | random_00 |
|
3710 ms | 29 MB |
| g++-sanitizer | random_01 |
|
3800 ms | 32 MB |
| g++-sanitizer | random_02 |
|
2732 ms | 16 MB |
| g++-sanitizer | small_00 |
|
17 ms | 9 MB |
| g++-sanitizer | small_01 |
|
16 ms | 10 MB |
| g++-sanitizer | small_02 |
|
17 ms | 10 MB |
| g++-sanitizer | small_03 |
|
19 ms | 10 MB |
| g++-sanitizer | small_04 |
|
21 ms | 10 MB |
| g++-sanitizer | small_05 |
|
18 ms | 11 MB |
| g++-sanitizer | small_06 |
|
16 ms | 11 MB |
| g++-sanitizer | small_07 |
|
18 ms | 11 MB |
| g++-sanitizer | small_08 |
|
21 ms | 11 MB |
| g++-sanitizer | small_09 |
|
22 ms | 11 MB |
| g++-sanitizer | small_random_00 |
|
21 ms | 12 MB |
| g++-sanitizer | small_random_01 |
|
23 ms | 12 MB |
| g++ | example_00 |
|
3 ms | 4 MB |
| g++ | max_random_00 |
|
728 ms | 21 MB |
| g++ | max_random_01 |
|
721 ms | 21 MB |
| g++ | max_random_02 |
|
721 ms | 21 MB |
| g++ | random_00 |
|
546 ms | 17 MB |
| g++ | random_01 |
|
589 ms | 20 MB |
| g++ | random_02 |
|
335 ms | 5 MB |
| g++ | small_00 |
|
3 ms | 4 MB |
| g++ | small_01 |
|
2 ms | 4 MB |
| g++ | small_02 |
|
2 ms | 4 MB |
| g++ | small_03 |
|
2 ms | 4 MB |
| g++ | small_04 |
|
2 ms | 4 MB |
| g++ | small_05 |
|
2 ms | 4 MB |
| g++ | small_06 |
|
2 ms | 4 MB |
| g++ | small_07 |
|
2 ms | 4 MB |
| g++ | small_08 |
|
2 ms | 4 MB |
| g++ | small_09 |
|
2 ms | 4 MB |
| g++ | small_random_00 |
|
3 ms | 4 MB |
| g++ | small_random_01 |
|
3 ms | 4 MB |