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 Ruby (2.7.1) (judge verdict: Time Limit Exceeded)

class LazySegtree
  attr_reader :d, :lz
  def initialize(v, e, id, op, mapping, composition)
    @n  = v.size.to_i
    @e  = e
    @id = id
    @op = op
    @mapping = mapping
    @composition = composition

    @log  = (@n - 1).bit_length.to_i
    @size = 1 << @log
    @d    = Array.new(2 * @size, e)
    @lz   = Array.new(@size, id)

    @n.times { |i| @d[@size + i] = v[i] }
    (@size - 1).downto(1) { |i| update(i) }
  end

  def set(pos, x)
    pos += @size
    @log.downto(1) { |i| push(pos >> i) }
    @d[pos] = x
    1.upto(@log) { |i| update(pos >> i) }
  end

  def get(pos)
    pos += @size
    @log.downto(1) { |i| push(pos >> i) }
    @d[pos]
  end

  def prod(l, r)
    # p "prodstart"
    return @e if l == r

    l += @size
    r += @size
    
    @log.downto(1) do |i|
      push(l >> i) if (l >> i) << i != l
      push(r >> i) if (r >> i) << i != r
    end
    
    sml = @e
    smr = @e
    while l < r
      if l.odd?
        sml = @op.call(sml, @d[l])
        l += 1
      end
      if r.odd?
        r -= 1
        smr = @op.call(@d[r], smr)
      end
      l >>= 1
      r >>= 1
    end

    @op.call(sml, smr)
  end

  def all_prod
    @d[1]
  end

  def apply(pos, f)
    pos += @size
    @log.downto(1) { |i| push(pos >> i) }
    @d[pos] = @mapping.call(f, @d[pos])
    1.upto(@log) { |i| update(pos >> i) }
  end

  def range_apply(l, r, f)
    return if l == r

    l += @size
    r += @size

    @log.downto(1) do |i|
      push(l >> i) if (l >> i) << i != l
      push((r - 1) >> i) if (r >> i) << i != r
    end

    l2 = l
    r2 = r
    while l < r
      (all_apply(l, f); l += 1) if l.odd?
      (r -= 1; all_apply(r, f)) if r.odd?
      l >>= 1
      r >>= 1
    end
    l = l2
    r = r2

    1.upto(@log) do |i|
      update(l >> i) if (l >> i) << i != l
      update((r - 1) >> i) if (r >> i) << i != r
    end
  end

  def max_right(l, &g)
    return @n if l == @n

    l += @size
    @log.downto(1) { |i| push(l >> i) }
    sm = @e

    loop do
      while l.even?
        l >>= 1
      end
      unless g.call(@op.call(sm, @d[l]))
        while l < @size
          push(l)
          l <<= 1
          if g.call(@op.call(sm, @d[l]))
            sm = @op.call(sm, @d[l])
            l += 1
          end
        end
        return l - @size
      end
      sm = @op.call(sm, @d[l])
      l += 1
      break if l & -l == l
    end
    @n
  end

  def update(k)
    @d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
  end

  def all_apply(k, f)
    @d[k] = @mapping.call(f, @d[k])
    @lz[k] = @composition.call(f, @lz[k]) if k < @size
  end

  def push(k)
    all_apply(2 * k, @lz[k])
    all_apply(2 * k + 1, @lz[k])
    @lz[k] = @id
  end
end

MOD = 998_244_353
# inf = 10 ** 20
# one = inf + 1

n, q = gets.to_s.split.map{ |e| e.to_i }
a    = gets.to_s.split.map { |e| (e.to_i << 32) + 1 }

op = Proc.new{ |s, t|
  sv, sn = s >> 32, s % (1 << 32)
  tv, tn = t >> 32, t % (1 << 32)
  (((sv + tv) % MOD) << 32) + sn + tn
}
mapping = Proc.new{ |f, a|
  fb, fc = (f >> 32), (f % (1 << 32))
  av, an = (a >> 32), (a % (1 << 32))
  (((fb * av + fc * an) % MOD) << 32) + an
}
composition =  Proc.new{ |f, g|
  fb, fc = f >> 32, f % (1 << 32)
  gb, gc = g >> 32, g % (1 << 32)
  ((fb * gb % MOD) << 32) + ((gc * fb + fc) % MOD)
}

lst = LazySegtree.new(a, 0, (1 << 32), op, mapping, composition)
ans = []
q.times do
  query = gets.to_s.split.map{ |e| e.to_i }
  if query[0] == 0
    _, l, r, a, b = query
    lst.range_apply(l, r, (a << 32) + b)
  else
    _, l, r = query
    ans << (lst.prod(l, r) >> 32)
  end
end

puts ans