/*
	Lazy SegmentTree
	last verified	: 2020/09/21, AtCoder
		problem			: https://atcoder.jp/contests/practice2/tasks/practice2_k
		submission		: https://atcoder.jp/contests/practice2/submissions/16932029
*/
#include <iostream>
#include <vector>
#include <functional>

template<long long P> long long modinv(long long n) {
	long long a = P, u = 1, v = 0;
	while (a) {
		long long t = n / a;
		n -= t * a; std::swap(n, a);
		u -= t * v; std::swap(u, v);
	}
	u %= P;
	if (u < 0) u += P;
	return u;
}

template<long long MOD> struct modint {
	long long value;
	modint(const long long& n = 0) : value(n) {
		value %= MOD;
		if (value < 0) value += MOD;
	}
	inline bool operator==(const modint<MOD>& right)const{return (value == right.value);}
	inline bool operator!=(const modint<MOD>& right)const{return (value != right.value);}
	inline bool operator<(const modint<MOD>& right)const{return (value < right.value);}
	inline bool operator>(const modint<MOD>& right)const{return (value > right.value);}
	inline bool operator<=(const modint<MOD>& right)const{return (value <= right.value);}
	inline bool operator>=(const modint<MOD>& right)const{return (value >= right.value);}
	modint<MOD> operator+(const modint<MOD>& right)const{modint<MOD> ret = value + right.value; return ret;}
	modint<MOD> operator-(const modint<MOD>& right)const{modint<MOD> ret = value - right.value; return ret;}
	modint<MOD> operator*(const modint<MOD>& right)const{modint<MOD> ret = value * right.value; return ret;}
	modint<MOD> operator/(const modint<MOD>& right)const{modint<MOD> ret = value * modinv<MOD>(right.value); return ret;}
	inline modint<MOD>& operator+=(modint<MOD>& right) {return *this = *this + right;}
	inline modint<MOD>& operator-=(modint<MOD>& right) {return *this = *this - right;}
	inline modint<MOD>& operator*=(modint<MOD>& right) {return *this = *this * right;}
	inline modint<MOD>& operator/=(modint<MOD>& right) {return *this = *this / right;}
	inline modint<MOD> operator-()const{return (*this) * -1;}
	inline modint<MOD>& operator++() {return (*this) += 1;}
	inline modint<MOD>& operator++(int) {return ++(*this) - 1;}
	inline modint<MOD>& operator--() {return (*this) -= 1;}
	inline modint<MOD>& operator--(int) {return --(*this) + 1;}
};
template<long long MOD> inline modint<MOD> operator+(const long long& left, const modint<MOD>& right) {
	return right + left;
}
template<long long MOD> inline modint<MOD> operator-(const long long& left, const modint<MOD>& right) {
	return right * -1 + left;
}
template<long long MOD> inline modint<MOD> operator*(const long long& left, const modint<MOD>& right) {
	return right * left;
}
template<long long P> inline modint<P> operator/(const long long& left, const modint<P>& right) {
	return modinv<P>(right.value) * (left % P);
}

template<long long MOD> modint<MOD> modpow(const modint<MOD>& a, const long long& n) {
	if (n == 0) return 1;
	if (a == 0) return 0;
	modint<MOD> ret = a;
	long long cnt = 1;
	while (cnt * 2 <= n) {
		ret *= ret;
		cnt *= 2;
	}
	return ret * modpow<MOD>(a, n - cnt);
}

std::vector<long long> factorial;
std::vector<long long> factorial_inv;

template<long long P> void make_table(const int& n) {
	factorial.resize(n + 1, 1);
	factorial_inv.resize(n + 1, 1);
	for (int i = 1; i <= n; i++) factorial[i] = factorial[i - 1] * i % P;
	factorial_inv[n] = modinv<P>(factorial[n]);
	for (int i = n - 1; i >= 0; i--) factorial_inv[i] = factorial_inv[i + 1] * (i + 1) % P;
}

template<long long P> modint<P> permutation(const int& n, const int& r) {
	if (n <= factorial.size()) return factorial[n] * factorial_inv[n - r];
	std::cerr << "attention : factorial table is not constructed" << std::endl;
	r = std::min(r, n - r);
	modint<P> ret = 1;
	for (int i = 0; i < r; i++) ret *= n - i;
	return ret;
}

template<long long P> modint<P> combination(const int& n, const int& r) {
	if (n <= factorial.size()) return permutation<P>(n, r) * factorial_inv[r];
	std::cerr << "attention : factorial table is not constructed" << std::endl;
	r = std::min(r, n - r);
	modint<P> ret = 1;
	for (int i = 0; i < r; i++) {
		ret *= n - i;
		ret /= i + 1;
	}
	return ret;
}

template<long long MOD> std::istream& operator>>(std::istream& is, modint<MOD>& target) {
	is >> target.value;
	target.value %= MOD;
	if (target.value < 0) target.value += MOD;
	return is;
}
template<long long MOD> inline std::ostream& operator<<(std::ostream& os, const modint<MOD>& target) {
	os << target.value;
	return os;
}

template<typename T, typename E, typename F, typename G, typename H> class lazy_segment_tree {
	int N;
	std::vector<T> value;
	std::vector<E> lazy;
	std::vector<bool> flag;

	void lazy_eval(const int& i, const int& l, const int& r) {
		if (lazy[i] == id_lz) return;
		value[i] = lz_to_val(value[i], lazy[i], r - l);
		if (r - l > 1) {
			lazy[i * 2] = op_lz(lazy[i * 2], lazy[i]);
			lazy[i * 2 + 1] = op_lz(lazy[i * 2 + 1], lazy[i]);
		}
		lazy[i] = id_lz;
	}

public :
	const F op_val;
	const G op_lz;
	const H lz_to_val;
	const T id_val;
	const E id_lz;

	lazy_segment_tree(const std::vector<T>& a, const F& f, const G& g, const H& h, const T& t, const E& e)
	: op_val(f), op_lz(g), lz_to_val(h), id_val(t), id_lz(e) {
		int n = a.size(), m = 1;
		while (m < n) m *= 2;
		N = m;
		value.resize(N * 2, id_val);
		lazy.resize(N * 2, id_lz);
		flag.resize(N * 2, false);
		for (int i = 0; i < n; i++) value[N + i] = a[i];
		for (int i = N - 1; i > 0; i--) value[i] = op_val(value[i * 2], value[i * 2 + 1]);
	}

	lazy_segment_tree(const int& n, const F& f, const G& g, const H& h, const T& t, const E& e)
	: op_val(f), op_lz(g), lz_to_val(h), id_val(t), id_lz(e) {
		int m = 1;
		while (m < n) m *= 2;
		N = m;
		value.resize(N * 2, id_val);
		lazy.resize(N * 2, id_lz);
		flag.resize(N * 2, false);
	}

	inline const int& size()const{return N;}

	void range_update(const int& L, const int& R, const E& e, const int& i = 1, const int& l = 0, int r = -1) {
		if (r == -1) r = N;
		if (r <= L || R <= l) return;
		if (L <= l && r <= R) {
			lazy[i] = op_lz(lazy[i], e);
			return;
		}
		lazy_eval(i, l, r);
		flag[i] = true;
		range_update(L, R, e, i * 2, l, (l + r) / 2);
		range_update(L, R, e, i * 2 + 1, (l + r) / 2, r);
	}

	T range_fold(const int& L, const int& R, const int& i = 1, const int& l = 0, int r = -1) {
		if (r == -1) r = N;
		if (r <= L || R <= l) return id_val;
		lazy_eval(i, l, r);
		if (L <= l && r <= R && !flag[i]) return value[i];
		if (L <= l && r <= R) flag[i] = false;
		T ret = op_val(
			range_fold(L, R, i * 2, l, (l + r) / 2),
			range_fold(L, R, i * 2 + 1, (l + r) / 2, r)
		);
		if (L <= l && r <= R) value[i] = ret;
		return ret;
	}

	inline const T& operator[](const int& i) {
		range_fold(i, i + 1);
		return value[N + i];
	}
};

int main() {
	int n, q;
	std::cin >> n >> q;
	constexpr int P = 998244353;
	std::vector<modint<P>> a(n);
	for (int i = 0; i < n; i++) std::cin >> a[i];

	auto f = [] (modint<P> a, modint<P> b) {return a + b;};
	auto g = [] (std::pair<modint<P>, modint<P>> a, std::pair<modint<P>, modint<P>> b) {
		return (std::pair<modint<P>, modint<P>>){
			a.first * b.first,
			a.second * b.first + b.second
		};
	};
	auto h = [] (modint<P> a, std::pair<modint<P>, modint<P>> b, int w) {
		return a * b.first + b.second * w;
	};
	lazy_segment_tree<modint<P>, std::pair<modint<P>, modint<P>>, decltype(f), decltype(g), decltype(h)> sg(
		a, f, g, h, 0, {1, 0}
	);

	while (q--) {
		int op, l, r;
		std::cin >> op >> l >> r;
		if (op == 0) {
			modint<P> b, c;
			std::cin >> b >> c;
			sg.range_update(l, r, {b, c});
		} else std::cout << sg.range_fold(l, r) << '\n';
	}

	return 0;
}

Measured memory_bytes: 31856