Buggy python submission (verdict: Time Limit Exceeded):
import os
import sys

import numpy as np


def solve(inp):
    SEGTREE_TABLES = []
    COMMON_STACK = np.zeros(10 ** 7, dtype=np.int64)
    MOD = 998244353
    DIV2 = 499122177

    def bit_length(n):
        ret = 0
        while n:
            n >>= 1
            ret += 1
        return ret

    def segtree_init(n):
        n2 = 1 << bit_length(n)
        table = np.zeros((n2 << 1, 3), dtype=np.int64)
        table[:, 1] = 1
        SEGTREE_TABLES.append(table)
        return len(SEGTREE_TABLES) - 1

    def segtree_build(ins, arr):
        table = SEGTREE_TABLES[ins]
        offset = table.shape[0] >> 1
        table[offset:offset + len(arr), 0] = arr
        for i in range(offset - 1, 0, -1):
            ch = i << 1
            table[i, 0] = (table[ch, 0] + table[ch + 1, 0]) % MOD

    def segtree_eval(table, offset, i):
        lazy_mul = table[i, 1]
        lazy_add = table[i, 2]
        if lazy_mul == 1 and lazy_add == 0:
            return
        if i < offset:
            ch = i << 1
            ch_add = lazy_add * DIV2 % MOD
            table[ch:ch + 2, 1:] *= lazy_mul
            table[ch:ch + 2, 2] += ch_add
            table[ch:ch + 2, 1:] %= MOD
        table[i, 0] = (table[i, 0] * lazy_mul + lazy_add) % MOD
        table[i, 1] = 1
        table[i, 2] = 0

    def segtree_bottomup(table, i):
        ch = i << 1
        sub = table[ch:ch + 2]
        table[i, 0] = (sub[:, 0] * sub[:, 1] + sub[:, 2]).sum() % MOD

    def segtree_range_update(ins, l, r, c, d):
        """ i for [l, r),  Ai ← Ai * c + d """
        table = SEGTREE_TABLES[ins]
        offset = table.shape[0] >> 1
        stack = COMMON_STACK
        stack[:5] = (1, 0, offset, c, d * offset % MOD)
        si = 5
        updated = []
        while si:
            i, a, b, mul, add = stack[si - 5:si]

            segtree_eval(table, offset, i)

            if b <= l or r <= a:
                si -= 5
                continue

            if l <= a and b <= r:
                table[i, 1] = table[i, 1] * mul % MOD
                table[i, 2] = (table[i, 2] * mul + add) % MOD
                si -= 5
                continue

            updated.append(i)

            add = add * DIV2 % MOD
            m = (a + b) // 2
            stack[si - 5:si] = (i << 1, a, m, mul, add)
            stack[si:si + 5] = ((i << 1) + 1, m, b, mul, add)
            si += 5

        while updated:
            i = updated.pop()
            segtree_bottomup(table, i)

    def segtree_query(ins, l, r):
        """ sum [l, r) """
        table = SEGTREE_TABLES[ins]
        offset = table.shape[0] >> 1
        stack = COMMON_STACK
        stack[:3] = (1, 0, offset)
        si = 3
        res = 0
        updated = []

        while si:
            i, a, b = stack[si - 3:si]

            segtree_eval(table, offset, i)

            if b <= l or r <= a:
                si -= 3
                continue

            if l <= a and b <= r:
                res = (res + table[i, 0]) % MOD
                si -= 3
                continue

            updated.append(i)

            m = (a + b) // 2
            stack[si - 3:si] = (i << 1, a, m)
            stack[si:si + 3] = ((i << 1) + 1, m, b)
            si += 3

        while updated:
            i = updated.pop()
            segtree_bottomup(table, i)

        return res

    def segtree_debug_print(ins):
        table = SEGTREE_TABLES[ins]
        offset = table.shape[0] >> 1
        for t in range(3):
            i = 1
            while i <= offset:
                print(table[i:2 * i, t])
                i <<= 1

    n = inp[0]
    aaa = inp[2:n + 2]

    ins = segtree_init(n)
    segtree_build(ins, aaa)

    qi = n + 2
    ans = []
    while qi < inp.size:
        t = inp[qi]
        if t == 0:
            # print(*inp[qi:qi + 5])
            l, r, b, c = inp[qi + 1:qi + 5]
            segtree_range_update(ins, l, r, b, c)
            qi += 5
        else:
            # print(*inp[qi:qi + 3])
            ans.append(segtree_query(ins, inp[qi + 1], inp[qi + 2]))
            qi += 3
        # segtree_debug_print(ins)
        # print()

    return ans


if sys.argv[-1] == 'ONLINE_JUDGE':
    from numba.pycc import CC

    cc = CC('my_module')
    cc.export('solve', '(i8[:],)')(solve)
    cc.compile()
    exit()

if os.name == 'posix':
    # noinspection PyUnresolvedReferences
    from my_module import solve
else:
    from numba import njit

    solve = njit('(i8[:],)', cache=True)(solve)
    print('compiled', file=sys.stderr)

inp = np.fromstring(sys.stdin.read(), dtype=np.int64, sep=' ')
ans = solve(inp)
print('\n'.join(map(str, ans)))


Fixed submission:
import os
import sys

import numpy as np


def solve(inp):
    SEGTREE_TABLES = []
    COMMON_STACK = np.zeros(10 ** 7, dtype=np.int64)
    MOD = 998244353
    DIV2 = 499122177

    def bit_length(n):
        ret = 0
        while n:
            n >>= 1
            ret += 1
        return ret

    def segtree_init(n):
        n2 = 1 << bit_length(n)
        table = np.zeros((3, n2 << 1), dtype=np.int64)
        table[1] = 1
        SEGTREE_TABLES.append(table)
        return len(SEGTREE_TABLES) - 1

    def segtree_build(ins, arr):
        table = SEGTREE_TABLES[ins]
        offset = table.shape[1] >> 1
        table[0, offset:offset + len(arr)] = arr
        for i in range(offset - 1, 0, -1):
            ch = i << 1
            table[0, i] = (table[0, ch] + table[0, ch + 1]) % MOD

    def segtree_eval(table, offset, i):
        lazy_mul = table[1, i]
        lazy_add = table[2, i]
        if i < offset:
            ch = i << 1
            ch_add = lazy_add * DIV2 % MOD
            table[1, ch] = table[1, ch] * lazy_mul % MOD
            table[2, ch] = (table[2, ch] * lazy_mul + ch_add) % MOD
            table[1, ch + 1] = table[1, ch + 1] * lazy_mul % MOD
            table[2, ch + 1] = (table[2, ch + 1] * lazy_mul + ch_add) % MOD
        table[0, i] = (table[0, i] * lazy_mul + lazy_add) % MOD
        table[1, i] = 1
        table[2, i] = 0

    def segtree_bottomup(table, i):
        lch = i << 1
        rch = lch + 1
        l_dat = (table[0, lch] * table[1, lch] + table[2, lch]) % MOD
        r_dat = (table[0, rch] * table[1, rch] + table[2, rch]) % MOD
        table[0, i] = (l_dat + r_dat) % MOD

    def segtree_range_update(ins, l, r, c, d):
        """ i for [l, r),  Ai ← Ai * c + d """
        table = SEGTREE_TABLES[ins]
        offset = table.shape[1] >> 1
        stack = COMMON_STACK
        stack[:5] = (1, 0, offset, c, d * offset % MOD)
        si = 5
        updated = []
        while si:
            i, a, b, mul, add = stack[si - 5:si]
            # print('affin', i, a, b, mul, add)

            segtree_eval(table, offset, i)

            if b <= l or r <= a:
                si -= 5
                continue

            if l <= a and b <= r:
                table[1, i] = table[1, i] * mul % MOD
                table[2, i] = (table[2, i] * mul + add) % MOD
                si -= 5
                continue

            updated.append(i)

            add = add * DIV2 % MOD
            m = (a + b) // 2
            stack[si - 5:si] = (i << 1, a, m, mul, add)
            stack[si:si + 5] = ((i << 1) + 1, m, b, mul, add)
            si += 5

        # print('update', updated)

        while updated:
            i = updated.pop()
            segtree_bottomup(table, i)

    def segtree_query(ins, l, r):
        """ sum [l, r) """
        table = SEGTREE_TABLES[ins]
        offset = table.shape[1] >> 1
        stack = COMMON_STACK
        stack[:3] = (1, 0, offset)
        si = 3
        res = 0
        updated = []

        while si:
            i, a, b = stack[si - 3:si]
            # print('query', i, a, b)

            segtree_eval(table, offset, i)

            if b <= l or r <= a:
                si -= 3
                continue

            if l <= a and b <= r:
                res = (res + table[0, i]) % MOD
                si -= 3
                continue

            updated.append(i)

            m = (a + b) // 2
            stack[si - 3:si] = (i << 1, a, m)
            stack[si:si + 3] = ((i << 1) + 1, m, b)
            si += 3

        while updated:
            i = updated.pop()
            segtree_bottomup(table, i)

        return res

    def segtree_debug_print(ins):
        table = SEGTREE_TABLES[ins]
        offset = table.shape[1] >> 1
        for t in range(3):
            i = 1
            while i <= offset:
                print(table[t, i:2 * i])
                i <<= 1

    n = inp[0]
    aaa = inp[2:n + 2]

    ins = segtree_init(n)
    segtree_build(ins, aaa)

    qi = n + 2
    ans = []
    while qi < inp.size:
        t = inp[qi]
        if t == 0:
            # print(*inp[qi:qi + 5])
            l, r, b, c = inp[qi + 1:qi + 5]
            segtree_range_update(ins, l, r, b, c)
            qi += 5
        else:
            # print(*inp[qi:qi + 3])
            ans.append(segtree_query(ins, inp[qi + 1], inp[qi + 2]))
            qi += 3
        # segtree_debug_print(ins)
        # print()

    return ans


if sys.argv[-1] == 'ONLINE_JUDGE':
    from numba.pycc import CC

    cc = CC('my_module')
    cc.export('solve', '(i8[:],)')(solve)
    cc.compile()
    exit()

if os.name == 'posix':
    # noinspection PyUnresolvedReferences
    from my_module import solve
else:
    from numba import njit

    solve = njit('(i8[:],)', cache=True)(solve)
    print('compiled', file=sys.stderr)

inp = np.fromstring(sys.stdin.read(), dtype=np.int64, sep=' ')
ans = solve(inp)
print('\n'.join(map(str, ans)))