// ---------- begin Lazy Segment Tree ----------
pub trait TE {
    type T: Clone;
    type E: Clone;
    fn fold(l: &Self::T, r: &Self::T) -> Self::T;
    fn eval(x: &Self::T, f: &Self::E) -> Self::T;
    fn merge(g: &Self::E, h: &Self::E) -> Self::E;
    fn e() -> Self::T;
    fn id() -> Self::E;
}

pub struct LazySegmentTree<R: TE> {
    size: usize,
    bit: usize,
    a: Vec<(R::T, R::E)>,
}

impl <R: TE> LazySegmentTree<R> {
    pub fn new(n: usize) -> LazySegmentTree<R> {
        let size = n.next_power_of_two();
        let bit = size.trailing_zeros() as usize;
        LazySegmentTree {
            size: size,
            bit: bit,
            a: vec![(R::e(), R::id()); 2 * size],
        }
    }
    pub fn build_by(z: &[R::T]) -> LazySegmentTree<R> {
        let mut seg = LazySegmentTree::<R>::new(z.len());
        for (a, z) in seg.a[seg.size..].iter_mut().zip(z.iter()) {
            a.0 = z.clone();
        }
        let a = &mut seg.a;
        for i in (1..seg.size).rev() {
            a[i].0 = R::fold(&a[2 * i].0, &a[2 * i + 1].0);
        }
        seg
    }
    fn apply(&mut self, x: usize, op: &R::E) {
        let node = &mut self.a[x];
        node.0 = R::eval(&node.0, op);
        node.1 = R::merge(&node.1, op);
    }
    fn propagate_at(&mut self, x: usize) {
        let mut op = R::id();
        std::mem::swap(&mut op, &mut self.a[x].1);
        self.apply(2 * x, &op);
        self.apply(2 * x + 1, &op);
    }
    fn save_at(&mut self, x: usize) {
        let a = &mut self.a;
        a[x].0 = R::fold(&a[2 * x].0, &a[2 * x + 1].0);
    }
    fn down(&mut self, x: usize) {
        let x = x + self.size;
        for i in (1..=self.bit).rev() {
            self.propagate_at(x >> i);
        }
    }
    fn save(&mut self, x: usize) {
        let mut x = (x + self.size) >> 1;
        while x > 0 {
            self.save_at(x);
            x >>= 1;
        }
    }
    pub fn set_at(&mut self, x: usize, val: R::T) {
        assert!(x < self.size);
        self.down(x);
        self.a[x + self.size] = (val, R::id());
        self.save(x);
    }
    pub fn update(&mut self, l: usize, r: usize, op: R::E) {
        assert!(l <= r && r <= self.size);
        if l == r {
            return;
        }
        self.down(l);
        self.down(r - 1);
        let mut x = l + self.size;
        let mut y = r + self.size;
        while x < y {
            if x & 1 == 1 {
                self.apply(x, &op);
                x += 1;
            }
            if y & 1 == 1 {
                y -= 1;
                self.apply(y, &op);
            }
            x >>= 1;
            y >>= 1;
        }
        self.down(l);
        self.down(r - 1);
        self.save(l);
        self.save(r - 1);
    }
    pub fn find(&mut self, l: usize, r: usize) -> R::T {
        assert!(l <= r && r <= self.size);
        if l == r {
            return R::e();
        }
        self.down(l);
        self.down(r - 1);
        let mut x = l + self.size;
        let mut y = r + self.size;
        let mut p = R::e();
        let mut q = R::e();
        while x < y {
            if x & 1 == 1 {
                p = R::fold(&p, &self.a[x].0);
                x += 1;
            }
            if y & 1 == 1 {
                y -= 1;
                q = R::fold(&self.a[y].0, &q);
            }
            x >>= 1;
            y >>= 1;
        }
        R::fold(&p, &q)
    }
}
// ---------- end Lazy Segment Tree ----------

use proconio::*;

const MOD: u64 = 998_244_353;

struct R;
impl TE for R {
    type T = (u64, u64);
    type E = (u64, u64);
    fn fold(l: &Self::T, r: &Self::T) -> Self::T {
        ((l.0 + r.0) % MOD, l.1 + r.1)
    }
    fn eval(x: &Self::T, f: &Self::E) -> Self::T {
        ((x.0 * f.0 + x.1 * f.1) % MOD, x.1)
    }
    fn merge(g: &Self::E, h: &Self::E) -> Self::E {
        (g.0 * h.0 % MOD, (g.1 * h.0 + h.1) % MOD)
    }
    fn e() -> Self::T {
        (0, 0)
    }
    fn id() -> Self::E {
        (1, 0)
    }
}

#[fastout]
fn run() {
    input! {
        n: usize,
        q: usize,
        a: [u64; n],
    }
    let mut seg = LazySegmentTree::<R>::new(n);
    for (i, a) in a.iter().enumerate() {
        seg.set_at(i, (*a, 1));
    }
    for _ in 0..q {
        input! {
            op: u8,
            l: usize,
            r: usize,
        }
        if op == 0 {
            input! {
                b: u64,
                c: u64,
            }
            seg.update(l, r, (b, c));
        } else {
            let ans = seg.find(l, r).0;
            println!("{}", ans);
        }
    }
}

fn main() {
    run();
}


Measured memory_bytes: 56968