This documentation is automatically generated by competitive-verifier/competitive-verifier
#define PROBLEM "https://judge.yosupo.jp/problem/range_affine_range_sum"
#include "algo/common.h"
/* #include */
#include "algo/ds/lazy_segtree.h"
#include "algo/math/modint.h"
using namespace std;
using namespace algo;
using ds::lazy_segtree;
using mint = math::static_modint<998244353>;
struct affine_sum {
using Value = mint;
using Update = pair<mint, mint>;
static Value op(Value a, Value b) {
return a + b;
}
static Value e() {
return 0;
}
static Update id() {
return {1, 0};
}
static Update composition(Update f, Update g) {
return {f.first * g.first, f.first * g.second + f.second};
}
static Value mapping(Update f, Value x, index_t len) {
return f.first * x + f.second * len;
}
};
void solve() {
int n, q;
cin >> n >> q;
vector<mint> a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
lazy_segtree<affine_sum> st(a);
for (int i = 0; i < q; i++) {
int typ, l, r;
cin >> typ >> l >> r;
if (typ == 0) {
int b, c;
cin >> b >> c;
st.apply(l, r - 1, {b, c});
} else {
cout << st.query(l, r - 1) << '\n';
}
}
}
signed main() {
cin.tie(nullptr)->sync_with_stdio(false);
// int t;
// cin >> t;
// while (t--)
solve();
}
#line 1 "verify/ds/lazy_segtree.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/range_affine_range_sum"
#line 2 "algo/common.h"
#ifndef PREPROCESS
#include <bits/stdc++.h>
#include <cassert>
#endif
namespace algo {
// Indices and sizes into library containers. Signed, so the usual "walk down to
// -1" loops still terminate; widening the whole library is a change here alone.
using index_t = int;
} // namespace algo
#line 3 "verify/ds/lazy_segtree.test.cpp"
/* #include */
#line 3 "algo/utils/bits.h"
namespace algo::utils {
// Returns number of set bits in x
constexpr int popcnt(int64_t x) {
return __builtin_popcountll(x);
}
// Returns floor(log_2(x))
constexpr int lg2(uint64_t x) {
return std::bit_width(x) - 1;
}
} // namespace algo::utils
#line 4 "algo/ds/lazy_segtree.h"
namespace algo::ds {
// The monoid a query folds over. repeat(x, len) is x folded with itself len
// times: what a segment of len equal cells collapses to.
template <typename T>
struct sum_monoid {
using Value = T;
static Value op(Value a, Value b) {
return a + b;
}
static Value e() {
return Value(0);
}
static Value repeat(Value x, index_t len) {
return x * len;
}
};
template <typename T>
struct min_monoid {
using Value = T;
static Value op(Value a, Value b) {
return std::min(a, b);
}
static Value e() {
return std::numeric_limits<Value>::max();
}
static Value repeat(Value x, index_t) {
return x;
}
};
template <typename T>
struct max_monoid {
using Value = T;
static Value op(Value a, Value b) {
return std::max(a, b);
}
static Value e() {
return std::numeric_limits<Value>::lowest();
}
static Value repeat(Value x, index_t) {
return x;
}
};
// Adds f to every cell of a segment. The + is on Value, not op, so a range add
// shifts a min or max by f instead of folding f into it.
template <typename M>
struct add_lazy : M {
using Value = typename M::Value;
using Update = Value;
static Update id() {
return Update(0);
}
static Update composition(Update f, Update g) {
return f + g;
}
static Value mapping(Update f, Value x, index_t len) {
return x + M::repeat(f, len);
}
};
// Overwrites every cell of a segment. Any Value may be written, so none is free
// to mean "nothing pending" and Update needs the extra nullopt. A write
// discards what it lands on, so of two writes the later wins.
template <typename M>
struct assign_lazy : M {
using Value = typename M::Value;
using Update = std::optional<Value>;
static Update id() {
return std::nullopt;
}
static Update composition(Update f, Update g) {
return f ? f : g;
}
static Value mapping(Update f, Value x, index_t len) {
return f ? M::repeat(*f, len) : x;
}
};
// P supplies the monoid (Value, op, e) that queries fold over, the monoid of
// pending updates (Update, composition, id) where composition(f, g) applies g
// first, and mapping(f, x), which applies an update to a whole fold rather than
// to one cell. mapping may take the number of cells x covers as a third
// argument, for updates that scale with segment length. Inheriting P is free
// and keeps its names reachable.
template <typename P>
struct lazy_segtree : P {
using Value = typename P::Value;
using Update = typename P::Update;
// If the default value for leaf elements is not identical (e.g. in the case
// that indices are stored) then you must use the alternative constructor
lazy_segtree(index_t _n) : lazy_segtree(std::vector<Value>(_n, P::e())) {
}
lazy_segtree(const std::vector<Value> &a)
: n((index_t)a.size()), sz((index_t)std::bit_ceil((uint32_t)n)),
lg(utils::lg2(sz)), d(2 * sz, P::e()), lz(sz, P::id()) {
std::copy(a.begin(), a.end(), d.begin() + sz);
for (index_t i = sz - 1; i >= 1; i--)
pull(i);
}
Value get(index_t p) {
assert(0 <= p && p < n);
p += sz;
push_down(p);
return d[p];
}
void set(index_t p, Value x) {
assert(0 <= p && p < n);
p += sz;
push_down(p);
d[p] = x;
for (index_t i = 1; i <= lg; i++)
pull(p >> i);
}
// Inclusive on [l, r]
Value query(index_t l, index_t r) {
assert(0 <= l && r < n);
if (l > r) return P::e();
l += sz, r += sz + 1;
push_down(l, r);
// Two accumulators keep the fold in index order, which ops that are
// not commutative need.
Value ml = P::e(), mr = P::e();
for (; l < r; l >>= 1, r >>= 1) {
if (l & 1) ml = P::op(ml, d[l++]);
if (r & 1) mr = P::op(d[--r], mr);
}
return P::op(ml, mr);
}
Value all() {
return d[1];
}
// Inclusive on [l, r]
void apply(index_t l, index_t r, Update f) {
assert(0 <= l && r < n);
if (l > r) return;
l += sz, r += sz + 1;
push_down(l, r);
index_t l0 = l, r0 = r;
for (index_t len = 1; l < r; l >>= 1, r >>= 1, len <<= 1) {
if (l & 1) all_apply(l++, f, len);
if (r & 1) all_apply(--r, f, len);
}
for (index_t i = 1; i <= lg; i++) {
if (((l0 >> i) << i) != l0) pull(l0 >> i);
if (((r0 >> i) << i) != r0) pull((r0 - 1) >> i);
}
}
friend std::ostream &operator<<(std::ostream &os, lazy_segtree t) {
// A parent precedes its children in index order, so one increasing
// sweep pushes every pending update out to the leaves.
for (index_t k = 1; k < t.sz; k++)
t.push(k, t.sz >> (utils::lg2(k) + 1));
os << "[";
bool first = true;
for (index_t i = 0; i < t.n; i++) {
if (!first) os << ", ";
first = false;
os << t.d[t.sz + i];
}
return os << "]";
}
private:
// A 1-indexed heap of 2 * sz nodes, the cells past n padded with e(). d[k]
// is always current; lz[k] is owed to k's children, never to k itself.
index_t n, sz, lg;
std::vector<Value> d;
std::vector<Update> lz;
void pull(index_t k) {
d[k] = P::op(d[2 * k], d[2 * k + 1]);
}
// len is the number of cells node k covers. Policies whose updates ignore
// segment length may leave the third parameter of mapping off.
void all_apply(index_t k, const Update &f, index_t len) {
if constexpr (requires { P::mapping(f, d[k], len); }) {
d[k] = P::mapping(f, d[k], len);
} else {
d[k] = P::mapping(f, d[k]);
}
if (k < sz) lz[k] = P::composition(f, lz[k]);
}
// len is the number of cells each child of node k covers
void push(index_t k, index_t len) {
all_apply(2 * k, lz[k], len);
all_apply(2 * k + 1, lz[k], len);
lz[k] = P::id();
}
// Clears every pending update above leaf p
void push_down(index_t p) {
for (index_t i = lg; i >= 1; i--)
push(p >> i, index_t(1) << (i - 1));
}
// Same for the two boundary paths of [l, r). A node wholly inside the range
// is used as a whole and its own value is already current, so nothing below
// it needs clearing.
void push_down(index_t l, index_t r) {
for (index_t i = lg; i >= 1; i--) {
if (((l >> i) << i) != l) push(l >> i, index_t(1) << (i - 1));
if (((r >> i) << i) != r) push((r - 1) >> i, index_t(1) << (i - 1));
}
}
};
template <typename T>
using add_sum = add_lazy<sum_monoid<T>>;
template <typename T>
using add_min = add_lazy<min_monoid<T>>;
template <typename T>
using add_max = add_lazy<max_monoid<T>>;
template <typename T>
using assign_sum = assign_lazy<sum_monoid<T>>;
template <typename T>
using assign_min = assign_lazy<min_monoid<T>>;
template <typename T>
using assign_max = assign_lazy<max_monoid<T>>;
} // namespace algo::ds
#line 3 "algo/math/common.h"
namespace algo::math {
constexpr int64_t safe_mod(int64_t x, int64_t m) {
x %= m;
if (x < 0) x += m;
return x;
}
// Returns (x ** n) % m
constexpr int64_t pow_mod_constexpr(int64_t x, int64_t n, int m) {
assert(0 <= n);
assert(1 <= m);
if (m == 1) return 0;
unsigned int _m = (unsigned int)(m);
uint64_t r = 1;
uint64_t y = safe_mod(x, m);
while (n) {
if (n & 1) r = (r * y) % _m;
y = (y * y) % _m;
n >>= 1;
}
return r;
}
struct barrett {
constexpr explicit barrett(uint64_t _m) : m(_m), im(-1ULL / _m) {
assert(1 <= _m);
}
uint64_t mod() const {
return m;
};
uint64_t reduce(uint64_t a) const {
uint64_t q = (uint64_t)((__uint128_t(im) * a) >> 64);
uint64_t r = a - q * m;
return r - (r >= m) * m;
}
private:
uint64_t m, im;
};
constexpr int64_t c_div(int64_t a, int64_t b) {
return a / b + ((a ^ b) > 0 && a % b);
}
constexpr int64_t f_div(int64_t a, int64_t b) {
return a / b - ((a ^ b) < 0 && a % b);
}
auto bpow(auto const &x, auto n, auto const &one, auto op) {
if (n == 0) {
return one;
} else {
auto t = bpow(x, n / 2, one, op);
t = op(t, t);
if (n % 2) {
t = op(t, x);
}
return t;
}
}
auto bpow(auto x, auto n, auto ans) {
return bpow(x, n, ans, std::multiplies{});
}
template <typename T>
T bpow(T const &x, auto n) {
return bpow(x, n, T(1));
}
// Returns a pair(g, x) s.t. g = gcd(a, n), xa = g (mod n), 0 <= x < n/g
// If r > 1 then a is not invertible mod n
constexpr std::pair<int64_t, int64_t> inv_gcd(int64_t a, int64_t n) {
a = safe_mod(a, n);
if (a == 0) return {n, 0};
int64_t t = 0, newt = 1;
int64_t r = n, newr = a;
while (newr) {
int64_t quotient = r / newr;
r -= newr * quotient;
t -= newt * quotient;
std::swap(r, newr);
std::swap(t, newt);
}
if (t < 0) t += n / r;
return {r, t};
}
} // namespace algo::math
#line 4 "algo/math/modint.h"
namespace algo::math {
// A modulus fixed at compile time: no state, and the division folds into a
// multiply-shift.
template <int Mod>
struct static_mod {
static constexpr int mod() {
return Mod;
}
static int reduce(uint64_t x) {
return (int)(x % (uint64_t)Mod);
}
};
// A modulus known only at run time, held for the extent of with_mod. Nesting is
// rejected: values built under the outer modulus would survive into the inner
// one. Use a second id to hold two moduli at once.
template <int id>
struct dynamic_mod {
static int mod() {
assert(armed);
return bt.mod();
}
static int reduce(uint64_t x) {
return (int)bt.reduce(x);
}
static auto with_mod(int m, auto callback) {
assert(1 <= m && !armed);
struct scoped {
~scoped() {
armed = false;
}
} _;
bt = barrett(m), armed = true;
return callback();
}
private:
static inline barrett bt{1};
static inline bool armed = false;
};
// P supplies mod() and reduce(). Inheriting it makes both reachable through the
// modint (as is with_mod), and an empty policy costs no space.
template <typename P>
struct modint : P {
modint() : v(0) {
}
modint(int64_t _v) {
v = (-P::mod() < _v && _v < P::mod()) ? _v : _v % P::mod();
if (v < 0) v += P::mod();
}
modint &operator+=(const modint &other) {
v += other.v;
if (v >= P::mod()) v -= P::mod();
return *this;
}
modint &operator-=(const modint &other) {
v -= other.v;
if (v < 0) v += P::mod();
return *this;
}
modint &operator*=(const modint &other) {
v = P::reduce((uint64_t)v * other.v);
return *this;
}
modint &operator/=(const modint &other) {
return *this = *this * other.inv();
}
modint &operator++() {
v++;
if (v == P::mod()) v = 0;
return *this;
}
modint &operator--() {
if (v == 0) v = P::mod();
v--;
return *this;
}
modint operator++(int) {
modint result = *this;
++*this;
return result;
}
modint operator--(int) {
modint result = *this;
--*this;
return result;
}
friend modint operator+(modint a, const modint &b) {
return a += b;
}
friend modint operator-(modint a, const modint &b) {
return a -= b;
}
friend modint operator*(modint a, const modint &b) {
return a *= b;
}
friend modint operator/(modint a, const modint &b) {
return a /= b;
}
friend modint operator-(modint a) {
return 0 - a;
}
modint inv() const {
auto eg = inv_gcd(v, P::mod());
assert(eg.first == 1);
return eg.second;
}
friend bool operator==(const modint &a, const modint &b) {
return a.v == b.v;
}
friend bool operator!=(const modint &a, const modint &b) {
return !(a == b);
}
explicit operator int() const {
return v;
}
friend std::ostream &operator<<(std::ostream &os, const modint &a) {
return os << a.v;
}
friend std::istream &operator>>(std::istream &is, modint &a) {
is >> a.v;
a.v = (-P::mod() < a.v && a.v < P::mod()) ? a.v : a.v % P::mod();
if (a.v < 0) a.v += P::mod();
return is;
}
private:
int v;
};
template <int Mod>
using static_modint = modint<static_mod<Mod>>;
template <int id = 0>
using dynamic_modint = modint<dynamic_mod<id>>;
} // namespace algo::math
#line 7 "verify/ds/lazy_segtree.test.cpp"
using namespace std;
using namespace algo;
using ds::lazy_segtree;
using mint = math::static_modint<998244353>;
struct affine_sum {
using Value = mint;
using Update = pair<mint, mint>;
static Value op(Value a, Value b) {
return a + b;
}
static Value e() {
return 0;
}
static Update id() {
return {1, 0};
}
static Update composition(Update f, Update g) {
return {f.first * g.first, f.first * g.second + f.second};
}
static Value mapping(Update f, Value x, index_t len) {
return f.first * x + f.second * len;
}
};
void solve() {
int n, q;
cin >> n >> q;
vector<mint> a(n);
for (int i = 0; i < n; i++)
cin >> a[i];
lazy_segtree<affine_sum> st(a);
for (int i = 0; i < q; i++) {
int typ, l, r;
cin >> typ >> l >> r;
if (typ == 0) {
int b, c;
cin >> b >> c;
st.apply(l, r - 1, {b, c});
} else {
cout << st.query(l, r - 1) << '\n';
}
}
}
signed main() {
cin.tie(nullptr)->sync_with_stdio(false);
// int t;
// cin >> t;
// while (t--)
solve();
}
| Env | Name | Status | Elapsed | Memory |
|---|---|---|---|---|
| g++ | example_00 |
|
2 ms | 4 MB |
| g++ | max_random_00 |
|
396 ms | 14 MB |
| g++ | max_random_01 |
|
387 ms | 14 MB |
| g++ | max_random_02 |
|
370 ms | 14 MB |
| g++ | random_00 |
|
323 ms | 13 MB |
| g++ | random_01 |
|
308 ms | 14 MB |
| g++ | random_02 |
|
214 ms | 5 MB |
| g++ | small_00 |
|
2 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 |
|
2 ms | 4 MB |
| g++ | small_random_01 |
|
2 ms | 4 MB |