#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using vl = vector<ll>;
template<class T> using vc = vector<T>;
template<class T> using vvc = vector<vector<T>>;

#define eb emplace_back
#define all(x) (x).begin(), (x).end()
#define rep(i, n) for (ll i = 0; i < (n); i++)
#define repr(i, n) for (ll i = (n)-1; i >= 0; i--)
#define repe(i, l, r) for (ll i = (l); i < (r); i++)
#define reper(i, l, r) for (ll i = (r)-1; i >= (l); i--)
#define repa(i,n) for (auto& i: n)

template<class T> inline bool chmax(T &a, const T &b) {if (a<b) { a=b; return 1;} return 0;}
template<class T> inline bool chmin(T &a, const T &b) {if (b<a) { a=b; return 1;} return 0;}
struct init{init(){cin.tie(0);ios::sync_with_stdio(false);cout<<fixed<<setprecision(15);}}init_;

#ifdef DEBUG
template <class T, class N> void verr(const T& a, const N& n) { rep(i, n) cerr << a[i] << " "; cerr << "\n" << flush; }
ll dbgt = 1; void err() { cerr << "passed " << dbgt++ << "\n" << flush; }
template<class H, class... T> void err(H&& h,T&&... t){ cerr<< h << (sizeof...(t)?" ":"\n") << flush; if(sizeof...(t)>0) err(forward<T>(t)...); }
#endif

const ll INF = 4e18;
const ld EPS = 1e-11;
const ld PI = acos(-1.0L);
// const ll MOD = 1e9 + 7;
const ll MOD = 998244353;
//--------------------------------------------------------------------------------//
// modint
template<int MOD> struct Fp {
    long long val;
    constexpr Fp(long long v = 0) noexcept : val(v % MOD) {
        if (val < 0) val += MOD;
    }
    constexpr int getmod() { return MOD; }
    constexpr Fp operator - () const noexcept {
        return val ? MOD - val : 0;
    }
    constexpr Fp operator + (const Fp& r) const noexcept { return Fp(*this) += r; }
    constexpr Fp operator - (const Fp& r) const noexcept { return Fp(*this) -= r; }
    constexpr Fp operator * (const Fp& r) const noexcept { return Fp(*this) *= r; }
    constexpr Fp operator / (const Fp& r) const noexcept { return Fp(*this) /= r; }
    constexpr Fp& operator += (const Fp& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Fp& operator -= (const Fp& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr Fp& operator *= (const Fp& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Fp& operator /= (const Fp& r) noexcept {
        long long a = r.val, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b; swap(a, b);
            u -= t * v; swap(u, v);
        }
        val = val * u % MOD;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr bool operator == (const Fp& r) const noexcept {
        return this->val == r.val;
    }
    constexpr bool operator != (const Fp& r) const noexcept {
        return this->val != r.val;
    }
    friend constexpr ostream& operator << (ostream &os, const Fp<MOD>& x) noexcept {
        return os << x.val;
    }
    friend constexpr Fp<MOD> modpow(const Fp<MOD> &a, long long n) noexcept {
        if (n == 0) return 1;
        auto t = modpow(a, n / 2, MOD);
        t = t * t;
        if (n & 1) t = t * a;
        return t;
    }
};
using mint = Fp<MOD>;

template <
    class typeData,
    class typeLazy, 
    class FOP,
    class FAC,
    class FME
>
struct LazySegTree {
    int n, height;
    // 値配列, 値の単位元
    vector<typeData> data;
    const typeData dataId;
    // 遅延配列, 遅延値の単位元
    vector<typeLazy> lazy;
    const typeLazy lazyId;

    const FOP fOperate;
    const FAC fAct;
    const FME fMerge;

    LazySegTree(
        int _n, typeData _did, typeLazy _lid,
        const FOP _op,
        const FAC _ac,
        const FME _me
    )
        : dataId(_did), lazyId(_lid), fOperate(_op), fAct(_ac), fMerge(_me){
        n = 1, height = 0;
        while (n < _n) n *= 2, height++;
        data = vector<typeData>(2 * n, dataId);
        lazy = vector<typeLazy>(2 * n, lazyId);
    }

    inline typeData act(int k){
        return lazy[k] == lazyId ? data[k] : fAct(data[k], lazy[k]);
    }

    inline void propagate(int k){
        if (lazy[k] == lazyId) return;
        lazy[2 * k + 0] = fMerge(lazy[2 * k + 0], lazy[k]);
        lazy[2 * k + 1] = fMerge(lazy[2 * k + 1], lazy[k]);
        data[k] = fAct(data[k], lazy[k]), lazy[k] = lazyId;
    }


    // [a, b)を更新
    inline void update(int a, int b, typeLazy x) {
        if (a == b) return;
        a += n, b += n - 1;
        for (int i = height; i > 0; i--) propagate(a >> i), propagate(b >> i);
        for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1) {
            if (l & 1) lazy[l] = fMerge(lazy[l], x), l++;
            if (r & 1) r--, lazy[r] = fMerge(lazy[r], x);
        }
        for (int l = a / 2, r = b / 2; l > 0; l >>= 1, r >>= 1) {
            data[l] = fOperate(act(2 * l + 0), act(2 * l + 1));
            data[r] = fOperate(act(2 * r + 0), act(2 * r + 1));
        }
    }

    // [l, r)の区間クエリ
    inline typeData query(int a, int b){
        if (a == b) return dataId;
        a += n, b += n - 1;
        for (int i = height; i > 0; i--) propagate(a >> i), propagate(b >> i);
        typeData Lret = dataId, Rret = dataId;
        for (int l = a, r = b + 1; l < r; l >>= 1, r >>= 1){
            if (l & 1) Lret = fOperate(Lret, act(l++));
            if (r & 1) Rret = fOperate(act(--r), Rret);
        }
        return fOperate(Lret, Rret);
    }

    inline void build(vector<typeData> vec){
        for (int i = 0; i < vec.size(); i++) data[i + n] = vec[i];
        for (int i = n - 1; i > 0; i--) data[i] = fOperate(data[2 * i + 0], data[2 * i + 1]);
    }

    // 添字でアクセス
    inline typeData& operator[](int i) {
        return data[i + n];
    }
};


// using typeData = ll;
// using typeLazy = ll;
// auto fop = [](typeData a, typeData b) { return min(a, b); }; // 要素ｘ要素
// auto fac = [](typeData a, typeLazy f) { return f; };         // 要素ｘ作用素
// auto fme = [](typeLazy f, typeLazy g) { return g; };         // 作用素ｘ作用素
// typeData dataid = INF, typeLazy lazyid = 0;                  // 要素単位元, 遅延値単位元
// LazySegTree<typeData, typeLazy, decltype(fop), decltype(fac), decltype(fme)> seg(N, dataId, lazyId, fop, fac, fme)

using P = pair<mint, mint>;
inline auto fop = [](P a, P b) { return P(a.first + b.first, a.second + b.second); };
inline auto fac = [](P a, P f) { return P(a.first * f.first + f.second * a.second, a.second); };
inline auto fme = [](P f, P g) { return P(f.first * g.first, f.second * g.first + g.second); };

int main() {
    ll N, Q;
    cin >> N >> Q;

    LazySegTree<P, P, decltype(fop), decltype(fac), decltype(fme)> seg(N, P(0, 1), P(1, 0), fop, fac, fme);

    vc<P> A(N, P(0, 1));
    rep(i, N) {
        ll a;
        cin >> a;
        A[i].first = a;
    }
    seg.build(A);

    rep(_, Q){
        ll q;
        cin >> q;
        if(q == 0){
            ll l, r, b, c;
            cin >> l >> r >> b >> c;
            seg.update(l, r, P(b, c));
        }else{
            ll l, r;
            cin >> l >> r;
            cout << seg.query(l, r).first << '\n';
        }
    }
}


Measured memory_bytes: 51424