This documentation is automatically generated by online-judge-tools/verification-helper
#define PROBLEM "https://judge.yosupo.jp/problem/point_set_range_composite_large_array"
#include <iostream>
#include "../../../lib/data_structure/dynamic_segment_tree.hpp"
#include "../../../lib/math/modint.hpp"
using namespace std;
using mint = ModInt<998244353>;
using F = pair<mint, mint>;
F op(F a, F b){
return {a.first * b.first, a.second * b.first + b.second};
}
F e(){
return {1, 0};
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, q; cin >> n >> q;
DynamicSegTree<F, op, e> seg(n);
for(int i = 0; i < q; i++){
int t; cin >> t;
if(t == 0){
int p, c, d; cin >> p >> c >> d;
seg.update(p, {c, d});
}else{
int l, r;
mint x;
cin >> l >> r >> x;
F res = seg.query(l, r);
cout << res.first * x + res.second << "\n";
}
}
}
#line 1 "test/library_checker/data_structure/point_set_range_composite_large_array_1.test.cpp"
#define PROBLEM "https://judge.yosupo.jp/problem/point_set_range_composite_large_array"
#include <iostream>
#line 2 "lib/data_structure/dynamic_segment_tree.hpp"
/**
* @brief Dynamic Segment Tree
* @see https://lorent-kyopro.hatenablog.com/entry/2021/03/12/025644
*/
#include <cassert>
#include <memory>
template <typename T, T (*op)(T, T), T(*e)()>
struct DynamicSegTree{
DynamicSegTree(int n) : n(n), root(nullptr) {}
private:
struct node;
using node_ptr = std::unique_ptr<node>;
struct node{
int index;
T value, product;
node_ptr left, right;
node(int index, T value)
: index(index),
value(value),
product(value),
left(nullptr),
right(nullptr) {}
void refresh() {
product = op(op(left ? left->product : e(), value), right ? right->product : e());
}
};
const int n;
node_ptr root;
void update(node_ptr& t, int a, int b, int i, T x) const {
if(!t){
t = std::make_unique<node>(i, x);
return;
}
if(t->index == i){
t->value = x;
t->refresh();
return;
}
int c = (a + b) >> 1;
if(i < c){
if(t->index < i) std::swap(t->index, i), std::swap(t->value, x);
update(t->left, a, c, i, x);
} else {
if(i < t->index) std::swap(i, t->index), std::swap(x, t->value);
update(t->right, c, b, i, x);
}
t->refresh();
}
T get(const node_ptr& t, int a, int b, int i) const {
if(!t) return e();
if(t->index == i) return t->value;
int c = (a + b) >> 1;
if(i < c) return get(t->left, a, c, i);
else return get(t->right, c, b, i);
}
T query(const node_ptr& t, int a, int b, int l, int r) const {
if(!t || b <= l || r <= a) return e();
if(l <= a && b <= r) return t->product;
int c = (a + b) >> 1;
T result = query(t->left, a, c, l, r);
if(l <= t->index && t->index < r) result = op(result, t->value);
return op(result, query(t->right, c, b, l, r));
}
void reset(node_ptr& t, int a, int b, int l, int r) const {
if(!t || b <= l || r <= a) return;
if(l <= a && b <= r){
t.reset();
return;
}
int c = (a + b) >> 1;
reset(t->left, a, c, l, r);
reset(t->right, c, b, l, r);
t->refresh();
}
template <class F>
int max_right(const node_ptr& t, int a, int b, int l, const F& f, T& product) const {
if(!t || b <= l) return n;
if(f(op(product, t->product))){
product = op(product, t->product);
return n;
}
int c = (a + b) >> 1;
int result = max_right(t->left, a, c, l, f, product);
if(result != n) return result;
if(l <= t->index) {
product = op(product, t->value);
if(!f(product)) return t->index;
}
return max_right(t->right, c, b, l, f, product);
}
template <class F>
int min_left(const node_ptr& t, int a, int b, int r, const F& f, T& product) const {
if(!t || r <= a) return 0;
if(f(op(t->product, product))){
product = op(t->product, product);
return 0;
}
int c = (a + b) >> 1;
int result = min_left(t->right, c, b, r, f, product);
if(result != 0) return result;
if(t->index < r){
product = op(t->value, product);
if(!f(product)) return t->index + 1;
}
return min_left(t->left, a, c, r, f, product);
}
public:
void update(int i, T x) {
assert(i < n);
update(root, 0, n, i, x);
}
T get(int i) const {
assert(i < n);
return get(root, 0, n, i);
}
T query(int l, int r) const {
assert(l <= r && r <= n);
return query(root, 0, n, l, r);
}
T all_query() const {
return root ? root->product : e();
}
void reset(int l, int r) {
assert(l <= r && r <= n);
return reset(root, 0, n, l, r);
}
template <bool (*f)(T)>
int max_right(int l) const {
return max_right(l, [](T x) { return f(x); });
}
template <class F>
int max_right(int l, const F& f) const {
assert(l <= n);
T product = e();
assert(f(product));
return max_right(root, 0, n, l, f, product);
}
template <bool (*f)(T)>
int min_left(int r) const {
return min_left(r, [](T x) { return f(x); });
}
template <class F>
int min_left(int r, const F& f) const {
assert(r <= n);
T product = e();
assert(f(product));
return min_left(root, 0, n, r, f, product);
}
};
#line 2 "lib/math/modint.hpp"
#line 5 "lib/math/modint.hpp"
/**
* @brief ModInt
* @docs docs/math/modint.md
*/
template <long long Modulus>
struct ModInt{
long long val;
static constexpr int mod() { return Modulus; }
constexpr ModInt(const long long _val = 0) noexcept : val(_val) {
normalize();
}
void normalize(){
val = (val % Modulus + Modulus) % Modulus;
}
inline ModInt &operator+=(const ModInt &rhs) noexcept {
if(val += rhs.val, val >= Modulus) val -= Modulus;
return *this;
}
inline ModInt &operator-=(const ModInt &rhs) noexcept {
if(val -= rhs.val, val < 0) val += Modulus;
return *this;
}
inline ModInt &operator*=(const ModInt &rhs) noexcept {
val = val * rhs.val % Modulus;
return *this;
}
inline ModInt &operator/=(const ModInt &rhs) noexcept {
val = val * inv(rhs.val).val % Modulus;
return *this;
}
inline ModInt &operator++() noexcept {
if(++val >= Modulus) val -= Modulus;
return *this;
}
inline ModInt operator++(int) noexcept {
ModInt t = val;
if(++val >= Modulus) val -= Modulus;
return t;
}
inline ModInt &operator--() noexcept {
if(--val < 0) val += Modulus;
return *this;
}
inline ModInt operator--(int) noexcept {
ModInt t = val;
if(--val < 0) val += Modulus;
return t;
}
inline ModInt operator-() const noexcept { return (Modulus - val) % Modulus; }
inline ModInt inv(void) const { return inv(val); }
ModInt pow(long long n) const {
assert(0 <= n);
ModInt x = *this, r = 1;
while(n){
if(n & 1) r *= x;
x *= x;
n >>= 1;
}
return r;
}
ModInt inv(const long long n) const {
long long a = n, b = Modulus, u = 1, v = 0;
while(b){
long long t = a / b;
a -= t * b; std::swap(a, b);
u -= t * v; std::swap(u, v);
}
u %= Modulus;
if(u < 0) u += Modulus;
return u;
}
friend inline ModInt operator+(const ModInt &lhs, const ModInt &rhs) noexcept { return ModInt(lhs) += rhs; }
friend inline ModInt operator-(const ModInt &lhs, const ModInt &rhs) noexcept { return ModInt(lhs) -= rhs; }
friend inline ModInt operator*(const ModInt &lhs, const ModInt &rhs) noexcept { return ModInt(lhs) *= rhs; }
friend inline ModInt operator/(const ModInt &lhs, const ModInt &rhs) noexcept { return ModInt(lhs) /= rhs; }
friend inline bool operator==(const ModInt &lhs, const ModInt &rhs) noexcept { return lhs.val == rhs.val; }
friend inline bool operator!=(const ModInt &lhs, const ModInt &rhs) noexcept { return lhs.val != rhs.val; }
friend inline std::istream &operator>>(std::istream &is, ModInt &x) noexcept {
is >> x.val;
x.normalize();
return is;
}
friend inline std::ostream &operator<<(std::ostream &os, const ModInt &x) noexcept { return os << x.val; }
};
#line 7 "test/library_checker/data_structure/point_set_range_composite_large_array_1.test.cpp"
using namespace std;
using mint = ModInt<998244353>;
using F = pair<mint, mint>;
F op(F a, F b){
return {a.first * b.first, a.second * b.first + b.second};
}
F e(){
return {1, 0};
}
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, q; cin >> n >> q;
DynamicSegTree<F, op, e> seg(n);
for(int i = 0; i < q; i++){
int t; cin >> t;
if(t == 0){
int p, c, d; cin >> p >> c >> d;
seg.update(p, {c, d});
}else{
int l, r;
mint x;
cin >> l >> r >> x;
F res = seg.query(l, r);
cout << res.first * x + res.second << "\n";
}
}
}