package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
)

var sc, wr = bufio.NewScanner(os.Stdin), bufio.NewWriter(os.Stdout)

func scanString() string   { sc.Scan(); return sc.Text() }
func scanRunes() []rune    { return []rune(scanString()) }
func scanInt() int         { a, _ := strconv.Atoi(scanString()); return a }
func scanInt64() int64     { a, _ := strconv.ParseInt(scanString(), 10, 64); return a }
func scanFloat64() float64 { a, _ := strconv.ParseFloat(scanString(), 64); return a }

func scanInts(n int) []int {
	a := make([]int, n)
	for i := 0; i < n; i++ {
		a[i] = scanInt()
	}
	return a
}

func debug(a ...interface{}) {
	if os.Getenv("ONLINE_JUDGE") == "false" {
		fmt.Fprintln(os.Stderr, a...)
	}
}

func abs(a int) int {
	if a < 0 {
		return -a
	}
	return a
}
func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

//•*¨*•.¸¸♪main•*¨*•.¸¸♪(　-ω-)ノ　(　・ω・)
func main() {
	defer wr.Flush()
	sc.Split(bufio.ScanWords)
	sc.Buffer(make([]byte, 10000), 1001001)

	n, q := scanInt(), scanInt()
	seg := newLazySegmentTree(n, node{0, 0}, onode{1, 0}, f, g, h)
	for i := 0; i < n; i++ {
		seg.set(i, node{scanInt(), 1})
	}
	seg.build()
	for i := 0; i < q; i++ {
		t := scanInt()
		if t == 0 {
			l, r, b, c := scanInt(), scanInt(), scanInt(), scanInt()
			seg.update(l, r, onode{b, c})
		} else {
			l, r := scanInt(), scanInt()
			fmt.Fprintln(wr, seg.query(l, r).a)
		}
	}
}

const mod = 998244353

func f(a, b node) node {
	return node{(a.a + b.a) % mod, a.sz + b.sz}
}

func g(a node, b onode) node {
	return node{(b.a*a.a%mod + a.sz*b.b%mod) % mod, a.sz}
}

func h(a, b onode) onode {
	return onode{b.a * a.a % mod, (b.b*a.a%mod + a.b) % mod}
}

type node struct{ a, sz int }
type onode struct{ a, b int }
type lazySegmentTree struct {
	d   []node
	lz  []onode
	n   int
	sz  int
	log int
	e   node
	id  onode
	f   func(a, b node) node
	g   func(a node, b onode) node
	h   func(a, b onode) onode
}

func newLazySegmentTree(n int, e node, id onode, f func(a, b node) node, g func(a node, b onode) node, h func(a, b onode) onode) *lazySegmentTree {
	sz, log := 1, 0
	for sz < n {
		sz <<= 1
		log++
	}
	d := make([]node, 2*sz)
	lz := make([]onode, 2*sz)
	for i := 0; i < 2*sz; i++ {
		d[i] = e
		lz[i] = id
	}
	s := lazySegmentTree{d, lz, n, sz, log, e, id, f, g, h}
	return &s
}

func (s lazySegmentTree) set(i int, a node) {
	s.d[i+s.sz] = a
}

func (s lazySegmentTree) build() {
	for i := s.sz - 1; i > 0; i-- {
		s.d[i] = s.f(s.d[2*i], s.d[2*i+1])
	}
}

func (s lazySegmentTree) get(k int) node {
	k += s.sz
	for i := s.log; i > 0; i-- {
		s.prop(k >> i)
	}
	return s.d[k]
}

func (s lazySegmentTree) update(l, r int, x onode) {
	l += s.sz
	r += s.sz
	for i := s.log; i > 0; i-- {
		if l>>i<<i != l {
			s.prop(l >> i)
		}
		if r>>i<<i != r {
			s.prop((r - 1) >> i)
		}
	}

	for a, b := l, r; a < b; a, b = a>>1, b>>1 {
		if a&1 == 1 {
			s.apply(a, x)
			a++
		}
		if b&1 == 1 {
			b--
			s.apply(b, x)
		}
	}

	for i := 1; i <= s.log; i++ {
		if l>>i<<i != l {
			k := l >> i
			s.d[k] = s.f(s.d[2*k], s.d[2*k+1])
		}
		if r>>i<<i != r {
			k := (r - 1) >> i
			s.d[k] = s.f(s.d[2*k], s.d[2*k+1])
		}
	}
}

func (s lazySegmentTree) query(l, r int) node {
	vl, vr := s.e, s.e
	l += s.sz
	r += s.sz
	for i := s.log; i > 0; i-- {
		if l>>i<<i != l {
			s.prop(l >> i)
		}
		if r>>i<<i != r {
			s.prop(r >> i)
		}
	}
	for l < r {
		if l&1 == 1 {
			vl = s.f(vl, s.d[l])
			l++
		}
		if r&1 == 1 {
			r--
			vr = s.f(s.d[r], vr)
		}
		l >>= 1
		r >>= 1
	}
	return s.f(vl, vr)
}

func (s lazySegmentTree) maxRight(l int, f func(v node) bool) int {
	if l == s.n {
		return s.n
	}
	v := s.e
	l += s.sz
	for i := s.log; i > 0; i-- {
		s.prop(l >> i)
	}
	for {
		for l&1 == 0 {
			l >>= 1
		}
		if !f(s.f(v, s.d[l])) {
			for l < s.sz {
				l <<= 1
				if f(s.f(v, s.d[l])) {
					v = s.f(v, s.d[l])
					l++
				}
			}
			return l - s.sz
		}
		v = s.f(v, s.d[l])
		l++
		if l&-l == l {
			break
		}
	}
	return s.n
}

func (s lazySegmentTree) minLeft(r int, f func(v node) bool) int {
	if r == 0 {
		return 0
	}
	v := s.e
	r += s.sz
	for i := s.log; i > 0; i-- {
		s.prop((r - 1) >> i)
	}
	for {
		r--
		for r > 1 && r&1 == 1 {
			r >>= 1
		}
		if !f(s.f(v, s.d[r])) {
			for r < s.sz {
				r = r<<1 + 1
				if f(s.f(v, s.d[r])) {
					v = s.f(v, s.d[r])
					r--
				}
			}
			return r + 1 - s.sz
		}
		v = s.f(v, s.d[r])
		if r&-r == r {
			break
		}
	}

	return 0
}

func (s lazySegmentTree) prop(k int) {
	s.apply(2*k, s.lz[k])
	s.apply(2*k+1, s.lz[k])
	s.lz[k] = s.id
}

func (s lazySegmentTree) apply(k int, a onode) {
	s.d[k] = s.g(s.d[k], a)
	if k < s.sz {
		s.lz[k] = s.h(a, s.lz[k])
	}
}


Measured memory_bytes: 60032