Problem:
Score : 100 points

Problem Statement

You are given an array a_0, a_1, ..., a_{N-1} of length N. Process Q queries of the following types.

0 l r b c: For each i = l, l+1, \dots, {r - 1}, set a_i \gets b \times a_i + c.

1 l r: Print \sum_{i = l}^{r - 1} a_i \bmod 998244353.

Constraints

1 \leq N, Q \leq 500000

0 \leq a_i, c < 998244353

1 \leq b < 998244353

0 \leq l < r \leq N

All values in Input are integer.

Input

Input is given from Standard Input in the following format:

N Q
a_0 a_1 ... a_{N - 1}
\textrm{Query}_0
\textrm{Query}_1
:
\textrm{Query}_{Q - 1}

Output

For each query of the latter type, print the answer.

Sample Input 1

5 7
1 2 3 4 5
1 0 5
0 2 4 100 101
1 0 3
0 1 3 102 103
1 2 5
0 2 5 104 105
1 0 5

Sample Output 1

15
404
41511
4317767

Solution in C# (.NET Core 3.1.201) (judge verdict: Wrong Answer)

#region いつもの
using AtCoderProject;
using System;
using System.Collections.Generic;
using System.Linq;
using static AtCoderProject.Global;
using BigInteger = System.Numerics.BigInteger;
using BitOperations = System.Numerics.BitOperations;
using IEnumerable = System.Collections.IEnumerable;
using IEnumerator = System.Collections.IEnumerator;
using StringBuilder = System.Text.StringBuilder;
using Unsafe = System.Runtime.CompilerServices.Unsafe;

namespace AtCoderProject
{
    using System.IO;
    using System.Text;
    using System.Diagnostics;
    using System.Runtime.CompilerServices;
    using System.Linq.Expressions;

    public static class Global
    {
        public static int Gcd(params int[] nums)
        {
            var gcd = nums[0];
            for (var i = 1; i < nums.Length; i++)
                gcd = Gcd(nums[i], gcd);
            return gcd;
        }
        public static int Gcd(int a, int b) => b > a ? Gcd(b, a) : (b == 0 ? a : Gcd(b, a % b));
        public static int Lcm(int a, int b) => a / Gcd(a, b) * b;
        public static int Lcm(params int[] nums)
        {
            var lcm = nums[0];
            for (var i = 1; i < nums.Length; i++)
                lcm = Lcm(lcm, nums[i]);
            return lcm;
        }
        public static long Gcd(params long[] nums)
        {
            var gcd = nums[0];
            for (var i = 1; i < nums.Length; i++)
                gcd = Gcd(nums[i], gcd);
            return gcd;
        }
        public static long Gcd(long a, long b) => b > a ? Gcd(b, a) : (b == 0 ? a : Gcd(b, a % b));
        public static long Lcm(long a, long b) => a / Gcd(a, b) * b;

        public static long Lcm(params long[] nums)
        {
            var lcm = nums[0];
            for (var i = 1; i < nums.Length; i++)
                lcm = Lcm(lcm, nums[i]);
            return lcm;
        }

        public static T[] NewArray<T>(int len0, T value) => new T[len0].Fill(value);
        public static T[] NewArray<T>(int len0, Func<T> factory)
        {
            var arr = new T[len0];
            for (int i = 0; i < arr.Length; i++) arr[i] = factory();
            return arr;
        }
        public static T[][] NewArray<T>(int len0, int len1, T value) where T : struct
        {
            var arr = new T[len0][];
            for (int i = 0; i < arr.Length; i++) arr[i] = NewArray(len1, value);
            return arr;
        }
        public static T[][] NewArray<T>(int len0, int len1, Func<T> factory)
        {
            var arr = new T[len0][];
            for (int i = 0; i < arr.Length; i++) arr[i] = NewArray(len1, factory);
            return arr;
        }
        public static T[][][] NewArray<T>(int len0, int len1, int len2, T value) where T : struct
        {
            var arr = new T[len0][][];
            for (int i = 0; i < arr.Length; i++) arr[i] = NewArray(len1, len2, value);
            return arr;
        }
        public static T[][][] NewArray<T>(int len0, int len1, int len2, Func<T> factory)
        {
            var arr = new T[len0][][];
            for (int i = 0; i < arr.Length; i++) arr[i] = NewArray(len1, len2, factory);
            return arr;
        }
        public static T[][][][] NewArray<T>(int len0, int len1, int len2, int len3, T value) where T : struct
        {
            var arr = new T[len0][][][];
            for (int i = 0; i < arr.Length; i++) arr[i] = NewArray(len1, len2, len3, value);
            return arr;
        }
        public static T[][][][] NewArray<T>(int len0, int len1, int len2, int len3, Func<T> factory)
        {
            var arr = new T[len0][][][];
            for (int i = 0; i < arr.Length; i++) arr[i] = NewArray(len1, len2, len3, factory);
            return arr;
        }


        public static long Pow(long x, int y)
        {
            long res = 1;
            for (; y > 0; y >>= 1)
            {
                if ((y & 1) == 1) res *= x;
                x *= x;
            }
            return res;
        }
        public static BigInteger ParseBigInteger(ReadOnlySpan<char> s)
        {
            /* 自前実装の方が速い */
            if (s[0] == '-') return -ParseBigInteger(s[1..]);
            BigInteger res;
            if (s.Length % 9 == 0)
                res = 0;
            else
            {
                res = new BigInteger(int.Parse(s.Slice(0, s.Length % 9)));
                s = s.Slice(s.Length % 9);
            }

            while (s.Length > 0)
            {
                var sp = s.Slice(0, 9);
                res *= 1000_000_000;
                res += int.Parse(sp);
                s = s.Slice(9);
            }
            return res;
        }
        public static int PopCount(int x) => BitOperations.PopCount((uint)x);
        public static int PopCount(long x) => BitOperations.PopCount((ulong)x);
        public static int PopCount(ulong x) => BitOperations.PopCount(x);
        public static int MSB(int x) => BitOperations.Log2((uint)x);
        public static int MSB(uint x) => BitOperations.Log2(x);
        public static int MSB(long x) => BitOperations.Log2((ulong)x);
        public static int MSB(ulong x) => BitOperations.Log2(x);
        public static int LSB(int x) => BitOperations.TrailingZeroCount((uint)x);
        public static int LSB(uint x) => BitOperations.TrailingZeroCount(x);
        public static int LSB(long x) => BitOperations.TrailingZeroCount((ulong)x);
        public static int LSB(ulong x) => BitOperations.TrailingZeroCount(x);

    }
    public static class Ext
    {

        public static bool UpdateMax<T>(this ref T r, T val) where T : struct, IComparable<T>
        {
            if (r.CompareTo(val) < 0) { r = val; return true; }
            return false;
        }
        public static bool UpdateMin<T>(this ref T r, T val) where T : struct, IComparable<T>
        {
            if (r.CompareTo(val) > 0) { r = val; return true; }
            return false;
        }
        public static T[] Fill<T>(this T[] arr, T value)
        {
            Array.Fill(arr, value);
            return arr;
        }
        public static T[] Sort<T>(this T[] arr) { Array.Sort(arr); return arr; }
        public static string[] Sort(this string[] arr) => Sort(arr, StringComparer.Ordinal);
        public static T[] Sort<T, U>(this T[] arr, Expression<Func<T, U>> selector) where U : IComparable<U> => Sort(arr, ExComparer<T>.CreateExp(selector));
        public static T[] Sort<T>(this T[] arr, Comparison<T> comparison) { Array.Sort(arr, comparison); return arr; }
        public static T[] Sort<T>(this T[] arr, IComparer<T> comparer) { Array.Sort(arr, comparer); return arr; }
        public static T[] Reverse<T>(this T[] arr) { Array.Reverse(arr); return arr; }
        public static (int index, T max) MaxBy<T>(this T[] arr) where T : IComparable<T>
        {
            T max = arr[0];
            int maxIndex = 0;
            for (int i = 0; i < arr.Length; i++)
            {
                if (max.CompareTo(arr[i]) < 0)
                {
                    max = arr[i];
                    maxIndex = i;
                }
            }
            return (maxIndex, max);
        }
        public static (int index, T max) MaxBy<T, TMax>(this T[] arr, Func<T, TMax> maxBySelector) where TMax : IComparable<TMax>
        {
            var maxItem = maxBySelector(arr[0]);
            var max = arr[0];
            int maxIndex = 0;
            for (int i = 0; i < arr.Length; i++)
            {
                var nx = maxBySelector(arr[i]);
                if (maxItem.CompareTo(nx) < 0)
                {
                    maxItem = nx;
                    max = arr[i];
                    maxIndex = i;
                }
            }
            return (maxIndex, max);
        }
        public static (TSource item, TMax max) MaxBy<TSource, TMax>
            (this IEnumerable<TSource> source, Func<TSource, TMax> maxBySelector)
            where TMax : IComparable<TMax>
        {
            TMax max;
            TSource maxByItem;
            var e = source.GetEnumerator();
            e.MoveNext();
            maxByItem = e.Current;
            max = maxBySelector(maxByItem);
            while (e.MoveNext())
            {
                var item = e.Current;
                var next = maxBySelector(item);
                if (max.CompareTo(next) < 0)
                {
                    max = next;
                    maxByItem = item;
                }
            }
            return (maxByItem, max);
        }
        public static (int index, T min) MinBy<T>(this T[] arr) where T : IComparable<T>
        {
            T min = arr[0];
            int minIndex = 0;
            for (int i = 0; i < arr.Length; i++)
            {
                if (min.CompareTo(arr[i]) > 0)
                {
                    min = arr[i];
                    minIndex = i;
                }
            }
            return (minIndex, min);
        }
        public static (int index, T min) MinBy<T, TMin>(this T[] arr, Func<T, TMin> minBySelector) where TMin : IComparable<TMin>
        {
            var minItem = minBySelector(arr[0]);
            var min = arr[0];
            int minIndex = 0;
            for (int i = 0; i < arr.Length; i++)
            {
                var nx = minBySelector(arr[i]);
                if (minItem.CompareTo(nx) > 0)
                {
                    minItem = nx;
                    min = arr[i];
                    minIndex = i;
                }
            }
            return (minIndex, min);
        }
        public static (TSource item, TMin min) MinBy<TSource, TMin>
            (this IEnumerable<TSource> source, Func<TSource, TMin> minBySelector)
            where TMin : IComparable<TMin>
        {
            TMin min;
            TSource minByItem;

            var e = source.GetEnumerator();
            e.MoveNext();
            minByItem = e.Current;
            min = minBySelector(minByItem);
            while (e.MoveNext())
            {
                var item = e.Current;
                var next = minBySelector(item);
                if (min.CompareTo(next) > 0)
                {
                    min = next;
                    minByItem = item;
                }
            }
            return (minByItem, min);
        }
        public static Dictionary<TKey, int> GroupCount<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) => source.GroupBy(keySelector).ToDictionary(g => g.Key, g => g.Count());
        public static Dictionary<TKey, int> GroupCount<TKey>(this IEnumerable<TKey> source) => source.GroupCount(i => i);
        public static Span<T> AsSpan<T>(this List<T> list, int start = 0) => Unsafe.As<Tuple<T[]>>(list).Item1.AsSpan(start, list.Count);
        public static ref T Get<T>(this T[] arr, int index)
        {
            if (index < 0)
                return ref arr[arr.Length + index];
            return ref arr[index];
        }
        public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> dic, TKey key)
        {
            dic.TryGetValue(key, out var v);
            return v;
        }
    }
    public static class ExComparer<T>
    {
        class ExpressionComparer<K> : IComparer<T> where K : IComparable<K>
        {
            private class ParameterReplaceVisitor : ExpressionVisitor
            {
                private readonly ParameterExpression from;
                private readonly ParameterExpression to;
                public ParameterReplaceVisitor(ParameterExpression from, ParameterExpression to)
                {
                    this.from = from;
                    this.to = to;
                }
                protected override Expression VisitParameter(ParameterExpression node) => node == from ? to : base.VisitParameter(node);
            }

            readonly Comparison<T> func;
            public ExpressionComparer(Expression<Func<T, K>> expression)
            {
                var paramA = expression.Parameters[0];
                var paramB = Expression.Parameter(typeof(T));
                var f2 = (Expression<Func<T, K>>)new ParameterReplaceVisitor(expression.Parameters[0], paramB).Visit(expression);
                var compExp = Expression.Lambda<Comparison<T>>(Expression.Call(
                        expression.Body,
                        typeof(K).GetMethod(nameof(IComparable<K>.CompareTo), new[] { typeof(K) }),
                        f2.Body),
                        paramA, paramB);
                this.func = compExp.Compile();
            }
            public int Compare(T x, T y) => func(x, y);
            public override bool Equals(object obj) => obj is ExpressionComparer<K> c && this.func == c.func;
            public override int GetHashCode() => func.GetHashCode();
        }
        class ReverseComparer : IComparer<T>
        {
            private static Comparer<T> orig = Comparer<T>.Default;
            public int Compare(T y, T x) => orig.Compare(x, y);
            public override bool Equals(object obj) => obj is ReverseComparer;
            public override int GetHashCode() => GetType().GetHashCode();
        }
        public static IComparer<T> CreateExp<K>(Expression<Func<T, K>> expression) where K : IComparable<K> => new ExpressionComparer<K>(expression);
        public static readonly IComparer<T> DefaultReverse = new ReverseComparer();
    }
    public class ΔDebugView<T> { private IEnumerable<T> collection; public ΔDebugView(IEnumerable<T> collection) { this.collection = collection ?? throw new ArgumentNullException(nameof(collection)); }[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items => collection.ToArray(); }


    [DebuggerStepThrough]
    public class ConsoleReader
    {
        const int BufSize = 1 << 12;
        private readonly byte[] buffer = new byte[BufSize];
        private readonly Stream input;
        private readonly Encoding encoding;
        private int pos = 0;
        private int len = 0;
        public ConsoleReader(Stream input, Encoding encoding) { this.input = input; this.encoding = encoding; }
        public ConsoleReader() : this(Console.OpenStandardInput(), Console.InputEncoding) { }
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        private void MoveNext() { if (++pos >= len) { len = input.Read(buffer, 0, buffer.Length); if (len == 0) { buffer[0] = 10; } pos = 0; } }

        public int Int
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                int res = 0;
                bool neg = false;
                while (buffer[pos] < 48) { neg = buffer[pos] == 45; MoveNext(); }
                do { res = checked(res * 10 + (buffer[pos] ^ 48)); MoveNext(); } while (48 <= buffer[pos]);
                return neg ? -res : res;
            }
        }
        public int Int0 => this.Int - 1;
        public long Long
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                long res = 0;
                bool neg = false;
                while (buffer[pos] < 48) { neg = buffer[pos] == 45; MoveNext(); }
                do { res = res * 10 + (buffer[pos] ^ 48); MoveNext(); } while (48 <= buffer[pos]);
                return neg ? -res : res;
            }
        }
        public long Long0 => this.Long - 1;
        public string String
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                var sb = new List<byte>();
                while (buffer[pos] <= 32) MoveNext();
                do { sb.Add(buffer[pos]); MoveNext(); } while (32 < buffer[pos]);
                return this.encoding.GetString(sb.ToArray());
            }
        }
        public string Ascii
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                var sb = new StringBuilder();
                while (buffer[pos] <= 32) MoveNext();
                do { sb.Append((char)buffer[pos]); MoveNext(); } while (32 < buffer[pos]);
                return sb.ToString();
            }
        }
        public string Line
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                var sb = new List<byte>();
                while (buffer[pos] <= 32) MoveNext();
                do { sb.Add(buffer[pos]); MoveNext(); } while (buffer[pos] != 10 && buffer[pos] != 13);
                return this.encoding.GetString(sb.ToArray());
            }
        }
        public char Char
        {
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            get
            {
                while (buffer[pos] <= 32) MoveNext();
                char res = (char)buffer[pos];
                MoveNext();
                return res;
            }
        }
        public double Double => double.Parse(this.Ascii);

        [DebuggerStepThrough]
        public struct RepeatReader
        {
            ConsoleReader cr;
            int count;
            public RepeatReader(ConsoleReader cr, int count) { this.cr = cr; this.count = count; }
            public T[] Select<T>(Func<ConsoleReader, T> factory) { var arr = new T[count]; for (var i = 0; i < count; i++) arr[i] = factory(cr); return arr; }
            public T[] Select<T>(Func<ConsoleReader, int, T> factory) { var arr = new T[count]; for (var i = 0; i < count; i++) arr[i] = factory(cr, i); return arr; }
            public string[] Line { get { var arr = new string[count]; for (var i = 0; i < count; i++) arr[i] = cr.Line; return arr; } }
            public string[] String { get { var arr = new string[count]; for (var i = 0; i < count; i++) arr[i] = cr.String; return arr; } }
            public string[] Ascii { get { var arr = new string[count]; for (var i = 0; i < count; i++) arr[i] = cr.Ascii; return arr; } }
            public int[] Int { get { var arr = new int[count]; for (var i = 0; i < count; i++) arr[i] = cr.Int; return arr; } }
            public int[] Int0 { get { var arr = new int[count]; for (var i = 0; i < count; i++) arr[i] = cr.Int0; return arr; } }
            public long[] Long { get { var arr = new long[count]; for (var i = 0; i < count; i++) arr[i] = cr.Long; return arr; } }
            public long[] Long0 { get { var arr = new long[count]; for (var i = 0; i < count; i++) arr[i] = cr.Long0; return arr; } }
            public double[] Double { get { var arr = new double[count]; for (var i = 0; i < count; i++) arr[i] = cr.Double; return arr; } }

            public static implicit operator int[](RepeatReader rr) => rr.Int;
            public static implicit operator long[](RepeatReader rr) => rr.Long;
            public static implicit operator double[](RepeatReader rr) => rr.Double;
            public static implicit operator string[](RepeatReader rr) => rr.Ascii;
        }
        public RepeatReader Repeat(int count) => new RepeatReader(this, count);

        [DebuggerStepThrough]
        public struct SplitReader
        {
            ConsoleReader cr;
            public SplitReader(ConsoleReader cr) { this.cr = cr; }
            public string[] String { get { while (cr.buffer[cr.pos] <= 32) cr.MoveNext(); var list = new List<string>(); do { if (cr.buffer[cr.pos] < 32) cr.MoveNext(); else list.Add(cr.String); } while (cr.buffer[cr.pos] != 10 && cr.buffer[cr.pos] != 13); return list.ToArray(); } }
            public string[] Ascii { get { while (cr.buffer[cr.pos] <= 32) cr.MoveNext(); var list = new List<string>(); do { if (cr.buffer[cr.pos] < 32) cr.MoveNext(); else list.Add(cr.Ascii); } while (cr.buffer[cr.pos] != 10 && cr.buffer[cr.pos] != 13); return list.ToArray(); } }
            public int[] Int { get { while (cr.buffer[cr.pos] <= 32) cr.MoveNext(); var list = new List<int>(); do { if (cr.buffer[cr.pos] < 32) cr.MoveNext(); else list.Add(cr.Int); } while (cr.buffer[cr.pos] != 10 && cr.buffer[cr.pos] != 13); return list.ToArray(); } }
            public int[] Int0 { get { while (cr.buffer[cr.pos] <= 32) cr.MoveNext(); var list = new List<int>(); do { if (cr.buffer[cr.pos] < 32) cr.MoveNext(); else list.Add(cr.Int0); } while (cr.buffer[cr.pos] != 10 && cr.buffer[cr.pos] != 13); return list.ToArray(); } }
            public long[] Long { get { while (cr.buffer[cr.pos] <= 32) cr.MoveNext(); var list = new List<long>(); do { if (cr.buffer[cr.pos] < 32) cr.MoveNext(); else list.Add(cr.Long); } while (cr.buffer[cr.pos] != 10 && cr.buffer[cr.pos] != 13); return list.ToArray(); } }
            public long[] Long0 { get { while (cr.buffer[cr.pos] <= 32) cr.MoveNext(); var list = new List<long>(); do { if (cr.buffer[cr.pos] < 32) cr.MoveNext(); else list.Add(cr.Long0); } while (cr.buffer[cr.pos] != 10 && cr.buffer[cr.pos] != 13); return list.ToArray(); } }
            public double[] Double { get { while (cr.buffer[cr.pos] <= 32) cr.MoveNext(); var list = new List<double>(); do { if (cr.buffer[cr.pos] < 32) cr.MoveNext(); else list.Add(cr.Double); } while (cr.buffer[cr.pos] != 10 && cr.buffer[cr.pos] != 13); return list.ToArray(); } }

            public static implicit operator int[](SplitReader sr) => sr.Int;
            public static implicit operator long[](SplitReader sr) => sr.Long;
            public static implicit operator double[](SplitReader sr) => sr.Double;
            public static implicit operator string[](SplitReader sr) => sr.Ascii;
        }
        public SplitReader Split => new SplitReader(this);

        public static implicit operator int(ConsoleReader cr) => cr.Int;
        public static implicit operator long(ConsoleReader cr) => cr.Long;
        public static implicit operator double(ConsoleReader cr) => cr.Double;
        public static implicit operator string(ConsoleReader cr) => cr.Ascii;
    }
    [DebuggerStepThrough]
    public class ConsoleWriter
    {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] public readonly StreamWriter sw;
        public ConsoleWriter() : this(Console.OpenStandardOutput(), Console.OutputEncoding) { }
        public ConsoleWriter(Stream output, Encoding encoding) { sw = new StreamWriter(output, encoding); }
        public void Flush() => sw.Flush();
        public ConsoleWriter WriteLine(ReadOnlySpan<char> obj) { sw.WriteLine(obj); return this; }
        public ConsoleWriter WriteLine<T>(T obj) { sw.WriteLine(obj.ToString()); return this; }
        public ConsoleWriter WriteLineJoin<T>(Span<T> col) => WriteMany(' ', (ReadOnlySpan<T>)col);
        public ConsoleWriter WriteLineJoin<T>(ReadOnlySpan<T> col) => WriteMany(' ', col);
        public ConsoleWriter WriteLineJoin<T>(IEnumerable<T> col) => WriteMany(' ', col);
        public ConsoleWriter WriteLineJoin<T>(params T[] col) => WriteMany(' ', col);
        public ConsoleWriter WriteLineJoin(params object[] col) => WriteMany(' ', col);
        public ConsoleWriter WriteLineJoin<T1, T2>(T1 v1, T2 v2)
        {
            sw.Write(v1.ToString()); sw.Write(' ');
            sw.WriteLine(v2.ToString()); return this;
        }
        public ConsoleWriter WriteLineJoin<T1, T2, T3>(T1 v1, T2 v2, T3 v3)
        {
            sw.Write(v1.ToString()); sw.Write(' ');
            sw.Write(v2.ToString()); sw.Write(' ');
            sw.WriteLine(v3.ToString()); return this;
        }
        public ConsoleWriter WriteLineJoin<T1, T2, T3, T4>(T1 v1, T2 v2, T3 v3, T4 v4)
        {
            sw.Write(v1.ToString()); sw.Write(' ');
            sw.Write(v2.ToString()); sw.Write(' ');
            sw.Write(v3.ToString()); sw.Write(' ');
            sw.WriteLine(v4.ToString()); return this;
        }
        public ConsoleWriter WriteLines<T>(Span<T> col) => WriteMany('\n', (ReadOnlySpan<T>)col);
        public ConsoleWriter WriteLines<T>(ReadOnlySpan<T> col) => WriteMany('\n', col);
        public ConsoleWriter WriteLines<T>(IEnumerable<T> col) => WriteMany('\n', col);
        public ConsoleWriter WriteLineGrid<T>(IEnumerable<IEnumerable<T>> cols)
        {
            foreach (var col in cols)
                WriteLineJoin(col);
            return this;
        }
        private ConsoleWriter WriteMany<T>(char sep, ReadOnlySpan<T> col)
        {
            var en = col.GetEnumerator();
            if (!en.MoveNext())
                return this;
            sw.Write(en.Current.ToString());
            while (en.MoveNext())
            {
                sw.Write(sep);
                sw.Write(en.Current.ToString());
            }
            sw.WriteLine();
            return this;
        }
        private ConsoleWriter WriteMany<T>(char sep, IEnumerable<T> col)
        {
            var en = col.GetEnumerator();
            if (!en.MoveNext())
                return this;
            sw.Write(en.Current.ToString());
            while (en.MoveNext())
            {
                sw.Write(sep);
                sw.Write(en.Current.ToString());
            }
            sw.WriteLine();
            return this;
        }
    }
}
public partial class Program
{
    [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] public ConsoleReader cr;
    [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)] public ConsoleWriter cw;
    public Program(ConsoleReader reader, ConsoleWriter writer) { this.cr = reader; this.cw = writer; System.Globalization.CultureInfo.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture; }
    static void Main() => new Program(new ConsoleReader(), new ConsoleWriter()).Run();
    public void Run()
    {
        var res = Calc();
        if (res is double)
            cw.WriteLine(Result((double)res));
        else if (res is bool)
            cw.WriteLine(Result((bool)res));
        else if (res != null)
            cw.WriteLine(res.ToString());
        cw.Flush();
    }
}
public partial class Program
{
    public static string Result(double d) => d.ToString("0.####################", System.Globalization.CultureInfo.InvariantCulture);
    #endregion
    public static string Result(bool b) => b ? "Yes" : "No";
    private object Calc()
    {
        int N = cr;
        int Q = cr;
        var seg = new SegmentTreeLazy(cr.Repeat(N).Select(cr => ((Mod)cr.Long, 1)));

        for (int q = 0; q < Q; q++)
        {
            if (cr.Int == 0)
            {
                seg.Apply(cr.Int, cr.Int, (cr.Long, cr.Long));
            }
            else
            {
                cw.WriteLine(seg[cr.Int..cr.Int]);
            }
        }

        return null;
    }
}
class SegmentTreeLazy : SegmentTreeLazyAbstract<(Mod v, int size), (Mod b, Mod c)>
{
    protected override (Mod v, int size) DefaultValue => (0, 0);
    protected override (Mod b, Mod c) DefaultLazy => (1, 0);
    protected override (Mod v, int size) Operate((Mod v, int size) v1, (Mod v, int size) v2) => (v1.v + v2.v, v1.size + v2.size);
    protected override (Mod v, int size) ApplyLazy((Mod v, int size) v, (Mod b, Mod c) l) => (l.b * v.v + l.c * v.size, v.size);
    protected override (Mod b, Mod c) Merge((Mod b, Mod c) l1, (Mod b, Mod c) l2) => (l1.b * l2.b, l1.b * l2.c + l1.c);
    public SegmentTreeLazy((Mod v, int size)[] initArray) : base(initArray) { }
    public SegmentTreeLazy(int size) : base(size) { }
}
[System.Diagnostics.DebuggerTypeProxy(typeof(SegmentTreeLazyAbstract<,>.SegmentTreeLazyDebugView))]
abstract class SegmentTreeLazyAbstract<TValue, TOp> where TValue : struct where TOp : struct
{
    protected virtual TValue DefaultValue => default;
    protected virtual TOp DefaultLazy => default;
    protected abstract TValue Operate(TValue v1, TValue v2);
    protected abstract TValue ApplyLazy(TValue v, TOp l);
    protected abstract TOp Merge(TOp l1, TOp l2);

    TValue[] tree;
    TOp[] lazy;
    public readonly int rootLength;
    public int Length { get; }
    private readonly int log;
    public SegmentTreeLazyAbstract(TValue[] initArray) : this(initArray.Length)
    {
        Array.Copy(initArray, 0, tree, rootLength, initArray.Length);
        for (int i = rootLength - 1; i >= 1; i--)
            Update(i);
    }
    public SegmentTreeLazyAbstract(int size)
    {
        this.Length = size;
        this.log = MSB(size - 1) + 1;
        rootLength = 1 << log;
        lazy = NewArray(rootLength, DefaultLazy);
        tree = NewArray(rootLength << 1, DefaultValue);
    }
    void Update(int index) => tree[index] = Operate(tree[2 * index], tree[2 * index + 1]);

    void AllApply(int k, TOp f)
    {
        tree[k] = ApplyLazy(tree[k], f);
        if (k < rootLength) lazy[k] = Merge(f, lazy[k]);
    }
    void Push(int k)
    {
        AllApply(2 * k, lazy[k]);
        AllApply(2 * k + 1, lazy[k]);
        lazy[k] = DefaultLazy;
    }
    public TValue this[int index]
    {
        set
        {
            index += rootLength;
            for (int i = log; i >= 1; i--) Push(index >> i);
            tree[index] = value;
            for (int i = 1; i <= log; i++) Update(index >> i);
        }
        get
        {
            index += rootLength;
            for (int i = log; i >= 1; i--) Push(index >> i);
            return tree[index];
        }
    }

    public TValue Slice(int from, int length) => Query(from, from + length);
    public TValue Query(int from, int toExclusive)
    {

        if (from == toExclusive) return DefaultValue;

        from += rootLength;
        toExclusive += rootLength;

        for (int i = log; i >= 1; i--)
        {
            if (((from >> i) << i) != from) Push(from >> i);
            if (((toExclusive >> i) << i) != toExclusive) Push(toExclusive >> i);
        }

        TValue sml = DefaultValue, smr = DefaultValue;
        while (from < toExclusive)
        {
            if ((from & 1) != 0) sml = Operate(sml, tree[from++]);
            if ((toExclusive & 1) != 0) smr = Operate(tree[--toExclusive], smr);
            from >>= 1;
            toExclusive >>= 1;
        }

        return Operate(sml, smr);
    }
    public TValue QueryAll() => tree[1];

    public void Apply(int from, int toExclusive, TOp f)
    {
        if (from == toExclusive) return;

        from += rootLength;
        toExclusive += rootLength;

        for (int i = log; i >= 1; i--)
        {
            if (((from >> i) << i) != from) Push(from >> i);
            if (((toExclusive >> i) << i) != toExclusive) Push((toExclusive - 1) >> i);
        }

        {
            int l2 = from, r2 = toExclusive;
            while (from < toExclusive)
            {
                if ((from & 1) != 0) AllApply(from++, f);
                if ((toExclusive & 1) != 0) AllApply(--toExclusive, f);
                from >>= 1;
                toExclusive >>= 1;
            }
            from = l2;
            toExclusive = r2;
        }

        for (int i = 1; i <= log; i++)
        {
            if (((from >> i) << i) != from) Update(from >> i);
            if (((toExclusive >> i) << i) != toExclusive) Update((toExclusive - 1) >> i);
        }
    }

    /** <summary>二分探索</summary><returns>[r = l もしくは f(op(a[l], a[l + 1], ..., a[r - 1])) = true]&amp;&amp;[r = n もしくは f(op(a[l], a[l + 1], ..., a[r])) = false]となるrのいずれか。aが単調ならば前者を満たす最大のr</returns>*/
    public int MaxRight(int left, Predicate<TValue> ok)
    {
        throw new NotImplementedException();
    }
    /** <summary>二分探索</summary><returns>[l = r もしくは f(op(a[l], a[l + 1], ..., a[r - 1])) = true]&amp;&amp;[l = 0 もしくは f(op(a[l - 1], a[l + 1], ..., a[r - 1])) = false]となるlのいずれか。aが単調ならば前者を満たす最小のl</returns>*/
    public int MinLeft(int rightExclude, Predicate<TValue> ok)
    {
        throw new NotImplementedException();
    }

    [System.Diagnostics.DebuggerDisplay("{" + nameof(value) + "}", Name = "{" + nameof(key) + ",nq}")]
    struct KeyValuePairs
    {
        string key;
        (TValue value, TOp lazy) value;

        public KeyValuePairs(string key, (TValue value, TOp lazy) value)
        {
            this.key = key;
            this.value = value;
        }
    }
    class SegmentTreeLazyDebugView
    {
        SegmentTreeLazyAbstract<TValue, TOp> segmentTree;
        public SegmentTreeLazyDebugView(SegmentTreeLazyAbstract<TValue, TOp> segmentTree)
        {
            this.segmentTree = segmentTree;
        }

        [System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.RootHidden)]
        public KeyValuePairs[] Tree
        {
            get
            {
                var keys = new List<KeyValuePairs>(segmentTree.tree.Length);
                for (var len = segmentTree.rootLength; len > 0; len >>= 1)
                {
                    var unit = segmentTree.rootLength / len;
                    for (var i = 0; i < len; i++)
                    {
                        var index = i + len;
                        if (unit == 1)
                            keys.Add(new KeyValuePairs($"[{i}]", (segmentTree.tree[index], segmentTree.lazy[index])));
                        else
                        {
                            var from = i * unit;
                            keys.Add(new KeyValuePairs($"[{from}-{from + unit})", (segmentTree.tree[index], segmentTree.lazy[index])));
                        }
                    }
                }
                return keys.ToArray();
            }
        }
    }
}
readonly struct Mod : IEquatable<Mod>
{
    public const long mod = 998244353;
    const bool useInvCache = true;
    public static readonly Mod invalid = Unsafe(-1);
    public readonly long val;
    public Mod(long val) { this.val = val % mod; if (this.val < 0) this.val += mod; }
    public static Mod Unsafe(long val)
    {
        var m = new Mod();
        System.Runtime.CompilerServices.Unsafe.As<Mod, long>(ref m) = val;
        return m;
    }
    public override bool Equals(object obj) => (obj is Mod) && this == ((Mod)obj);
    public bool Equals(Mod obj) => this.val == obj.val;
    public override int GetHashCode() => val.GetHashCode();
    public override string ToString() => val.ToString();
    public static implicit operator Mod(long x) => new Mod(x);
    public static implicit operator Mod(ConsoleReader cr) => new Mod(cr.Long);
    public static Mod operator -(Mod x) => new Mod(-x.val);
    public static Mod operator +(Mod x, Mod y) => new Mod(x.val + y.val);
    public static Mod operator -(Mod x, Mod y) => new Mod(x.val - y.val);
    public static Mod operator *(Mod x, Mod y) => new Mod(x.val * y.val);
    public static Mod operator /(Mod x, Mod y) => x * y.Inverse();
    public static bool operator ==(Mod x, Mod y) => x.val == y.val;
    public static bool operator !=(Mod x, Mod y) => x.val != y.val;

    #region Inverse
    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    static (long x, long y, long d) EuclideanInverseCore(long a, long mod)
    {
        // ax+by=dの解を求める
        // (u,v,a) => (x,y,d)となっている
        // dは最終的にaとbのgcdとなる
        long b = mod, u = 1, v = 0;
        while (b > 0)
        {
            long t = a / b;
            (a, b) = (b, a - t * b);
            (u, v) = (v, u - t * v);
        }
        return (u, v, a);
    }

    static long[] MakeInverseCache()
    {
        var res = new long[1 + (int)Math.Sqrt(mod)];
        res[1] = 1;
        for (int i = 2; i < res.Length; i++)
        {
            res[i] = (-res[mod % i] * (mod / i)) % mod;
        }
        return res;
    }
    static long[] _InvCache;
    static long[] InvCache => _InvCache ??= MakeInverseCache();
    static Mod EuclideanInverseCache(long a)
    {
        var cache = InvCache;
        long b = mod, u = 1, v = 0;
        while (b > 0)
        {
            if (0 <= a && a < cache.Length)
                return cache[a] * u;
            long t = a / b;
            (a, b) = (b, a - t * b);
            (u, v) = (v, u - t * v);
        }
        return u;
    }
    public Mod Inverse() => useInvCache ? EuclideanInverseCache(val) : EuclideanInverseCore(val, mod).x;
    #endregion Inverse

    public static Mod Pow(Mod x, int y)
    {
        Mod res = 1;
        for (; y > 0; y >>= 1)
        {
            if ((y & 1) == 1) res *= x;
            x *= x;
        }
        return res;
    }
    public Mod Pow(int y) => Pow(this, y);
    public static long EuclideanInverse(long a, long mod)
    {
        var u = EuclideanInverseCore(a, mod).x % mod;
        if (u < 0) u += mod;
        return u;
    }

    /**<summary>中国剰余定理。<paramref name="r"/>[i] mod <paramref name="m"/>[i]を満たすものを返す。</summary><returns><paramref name="mod"/>(<paramref name="m"/>[i]のLCM)での解<paramref name="y"/>を返す。答えがない場合は (0,0)、引数が空の時は (0,1)を返す。</returns>*/
    public static (long y, long mod) Crt(IReadOnlyCollection<long> r, IReadOnlyCollection<long> m)
    {
        System.Diagnostics.Debug.Assert(r.Count == m.Count, $"{nameof(r)}.Count != {nameof(m)}.Count");

        long r0 = 0, m0 = 1;
        foreach (var (rr, mm) in r.Zip(m))
        {
            long r1 = rr % mm, m1 = mm;
            if (r1 < 0) r1 += mm;
            if (m0 < m1)
            {
                (r1, r0) = (r0, r1);
                (m1, m0) = (m0, m1);
            }
            if (m0 % m1 == 0)
            {
                if (r0 % m1 != r1) return (0, 0);
                continue;
            }
            var (im, _, g) = EuclideanInverseCore(m0, m1);

            long u1 = (m1 / g);
            // |r1 - r0| < (m0 + m1) <= lcm(m0, m1)
            if ((r1 - r0) % g != 0) return (0, 0);

            // u1 * u1 <= m1 * m1 / g / g <= m0 * m1 / g = lcm(m0, m1)
            long x = (r1 - r0) / g % u1 * im % u1;

            // |r0| + |m0 * x|
            // < m0 + m0 * (u1 - 1)
            // = m0 + m0 * m1 / g - m0
            // = lcm(m0, m1)
            r0 += x * m0;
            m0 *= u1;  // -> lcm(m0, m1)
            if (r0 < 0) r0 += m0;
        }
        return (r0, m0);
    }

    public static Factors CreateFactor(int max) => new Factors(max);
    public class Factors
    {
        readonly Mod[] fac, finv;
        public Factors(int max)
        {
            ++max;
            var inv = new Mod[max];
            fac = new Mod[max]; finv = new Mod[max];
            fac[0] = fac[1] = 1;
            finv[0] = finv[1] = 1;
            inv[1] = 1;
            for (var i = 2; i < max; i++)
            {
                fac[i] = fac[i - 1] * i;
                inv[i] = mod - inv[mod % i].val * (mod / i) % mod;
                finv[i] = finv[i - 1] * inv[i];
            }
        }

        /** <summary>組み合わせ関数(二項係数)</summary> */
        public Mod Combination(int n, int k)
        {
            if (n < k) return 0;
            if (n < 0 || k < 0) return 0;
            return fac[n] * finv[k] * finv[n - k];
        }

        public Mod Factorial(int n) => fac[n];
        public Mod FactorialInvers(int n) => finv[n];
    }
}
static class ModExt
{
    public static Mod Sum(this IEnumerable<Mod> source)
    {
        Mod sum = 0;
        foreach (var v in source) sum += v;
        return sum;
    }
}