Problem:


Score : 500 points

Problem Statement

You have a string S of length N.
Initially, all characters in S are 1s.

You will perform queries Q times.
In the i-th query, you are given two integers L_i, R_i and a character D_i (which is a digit).
Then, you must replace all characters from the L_i-th to the R_i-th (inclusive) with D_i.

After each query, read the string S as a decimal integer, and print its value modulo 998,244,353.

Constraints

1 \leq N, Q \leq 200,000

1 \leq L_i \leq R_i \leq N

1 \leq D_i \leq 9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N Q
L_1 R_1 D_1
:
L_Q R_Q D_Q

Output

Print Q lines.
In the i-th line print the value of S after the i-th query, modulo 998,244,353.

Sample Input 1

8 5
3 6 2
1 4 7
3 8 3
2 2 2
4 5 1

Sample Output 1

11222211
77772211
77333333
72333333
72311333

Sample Input 2

200000 1
123 456 7

Sample Output 2

641437905

Don't forget to take the modulo.



Sample input:
8 5
3 6 2
1 4 7
3 8 3
2 2 2
4 5 1


Sample output:
11222211
77772211
77333333
72333333
72311333

Submission status: Runtime Error

Solution code:
MOD = 998244353
class LazySegmentTree:  # from https://atcoder.jp/contests/practice2/submissions/16598122
    __slots__ = ["n", "data", "lazy", "me", "oe", "fmm", "fmo", "foo"]

    def __init__(self, monoid_data, monoid_identity, operator_identity, func_monoid_monoid, func_monoid_operator,
                func_operator_operator):
        self.me = monoid_identity
        self.oe = operator_identity
        self.fmm = func_monoid_monoid
        self.fmo = func_monoid_operator
        self.foo = func_operator_operator

        self.n = len(monoid_data)
        self.data = monoid_data*2
        for i in range(self.n-1, 0, -1):
            self.data[i] = self.fmm(self.data[2*i], self.data[2*i+1])
        self.lazy = [self.oe]*(self.n*2)

    def replace(self, index, value):
        index += self.n

        # propagation
        for shift in range(index.bit_length()-1, 0, -1):
            i = index>>shift
            self.lazy[2*i] = self.foo(self.lazy[2*i], self.lazy[i])
            self.lazy[2*i+1] = self.foo(self.lazy[2*i+1], self.lazy[i])
            self.data[i] = self.fmo(self.data[i], self.lazy[i])
            self.lazy[i] = self.oe

        # update
        self.data[index] = value
        self.lazy[index] = self.oe

        # recalculation
        i = index
        while i > 1:
            i //= 2
            self.data[i] = self.fmm(self.fmo(self.data[2*i], self.lazy[2*i]),
                                    self.fmo(self.data[2*i+1], self.lazy[2*i+1]))
            self.lazy[i] = self.oe

    def effect(self, l, r, operator):
        l += self.n
        r += self.n

        # preparing indices
        indices = []
        l0 = (l//(l&-l)) >> 1
        r0 = (r//(r&-r)-1) >> 1
        while r0 > l0:
            indices.append(r0)
            r0 >>= 1
        while l0 > r0:
            indices.append(l0)
            l0 >>= 1
        while l0 and l0 != r0:
            indices.append(r0)
            r0 >>= 1
            if l0 == r0:
                break
            indices.append(l0)
            l0 >>= 1
        while r0:
            indices.append(r0)
            r0 >>= 1

        # propagation
        for i in reversed(indices):
            self.lazy[2*i] = self.foo(self.lazy[2*i], self.lazy[i])
            self.lazy[2*i+1] = self.foo(self.lazy[2*i+1], self.lazy[i])
            self.data[i] = self.fmo(self.data[i], self.lazy[i])
            self.lazy[i] = self.oe

        # effect
        while l < r:
            if l&1:
                self.lazy[l] = self.foo(self.lazy[l], operator)
                l += 1
            if r&1:
                r -= 1
                self.lazy[r] = self.foo(self.lazy[r], operator)
            l >>= 1
            r >>= 1

        # recalculation
        for i in indices:
            self.data[i] = self.fmm(self.fmo(self.data[2*i], self.lazy[2*i]),
                                    self.fmo(self.data[2*i+1], self.lazy[2*i+1]))
            self.lazy[i] = self.oe

    def folded(self, l, r):
        l += self.n
        r += self.n

        # preparing indices
        indices = []
        l0 = (l//(l&-l))//2
        r0 = (r//(r&-r)-1)//2
        while r0 > l0:
            indices.append(r0)
            r0 >>= 1
        while l0 > r0:
            indices.append(l0)
            l0 >>= 1
        while l0 and l0 != r0:
            indices.append(r0)
            r0 >>= 1
            if l0 == r0:
                break
            indices.append(l0)
            l0 >>= 1
        while r0:
            indices.append(r0)
            r0 >>= 1

        # propagation
        for i in reversed(indices):
            self.lazy[2*i] = self.foo(self.lazy[2*i], self.lazy[i])
            self.lazy[2*i+1] = self.foo(self.lazy[2*i+1], self.lazy[i])
            self.data[i] = self.fmo(self.data[i], self.lazy[i])
            self.lazy[i] = self.oe

        # fold
        left_folded = self.me
        right_folded = self.me
        while l < r:
            if l&1:
                left_folded = self.fmm(left_folded, self.fmo(self.data[l], self.lazy[l]))
                l += 1
            if r&1:
                r -= 1
                right_folded = self.fmm(self.fmo(self.data[r], self.lazy[r]), right_folded)
            l >>= 1
            r >>= 1
        return self.fmm(left_folded, right_folded)
class ModInt:
    def __init__(self, x):
        self.x = x % MOD

    def __str__(self):
        return str(self.x)

    __repr__ = __str__

    def __add__(self, other):
        return (
            ModInt(self.x + other.x) if isinstance(other, ModInt) else
            ModInt(self.x + other)
        )

    def __sub__(self, other):
        return (
            ModInt(self.x - other.x) if isinstance(other, ModInt) else
            ModInt(self.x - other)
        )

    def __mul__(self, other):
        return (
            ModInt(self.x * other.x) if isinstance(other, ModInt) else
            ModInt(self.x * other)
        )

    def __truediv__(self, other):
        return (
            ModInt(
                self.x * pow(other.x, MOD - 2, MOD)
            ) if isinstance(other, ModInt) else
            ModInt(self.x * pow(other, MOD - 2, MOD))
        )

    def __pow__(self, other):
        return (
            ModInt(pow(self.x, other.x, MOD)) if isinstance(other, ModInt) else
            ModInt(pow(self.x, other, MOD))
        )

    __radd__ = __add__

    def __rsub__(self, other):
        return (
            ModInt(other.x - self.x) if isinstance(other, ModInt) else
            ModInt(other - self.x)
        )

    __rmul__ = __mul__

    def __rtruediv__(self, other):
        return (
            ModInt(
                other.x * pow(self.x, MOD - 2, MOD)
            ) if isinstance(other, ModInt) else
            ModInt(other * pow(self.x, MOD - 2, MOD))
        )

    def __rpow__(self, other):
        return (
            ModInt(pow(other.x, self.x, MOD)) if isinstance(other, ModInt) else
            ModInt(pow(other, self.x, MOD))
        )
def main():
    import sys
    sys.setrecursionlimit(311111)
    # import numpy as np
    ikimasu = sys.stdin.buffer.readline
    ini = lambda: int(ins())
    ina = lambda: list(map(int, ikimasu().split()))
    ins = lambda: ikimasu().strip()
    n,q  = ina()

    tmp = [(ModInt(1),ModInt(1)) for i in range(0,n)]
    tmpx = ModInt(1)
    tmpx1 = ModInt(1)
    ten = []
    one = []
    for i in range(31111):
        ten.append(tmpx)
        one.append(tmpx1)
        tmpx1*=10
        tmpx1+=1
        tmpx*=10
    # print(ten)
    def op(x1,x2):
        val1,size1 = x1
        val2,size2 = x2
        size = size1+size2
        val = val1*ten[int(str((size2)))]+val2
        return val,size
    e = (0,0)
    def maptmp(s,f):
        if(f == -1):
            return s
        else:
            return f*one[int(str(s[1]))-1],s[1]
    def comp(g,f):
        return f if f!=-1 else g

    ident = -1
    tmptree = LazySegmentTree(tmp,e,ident,op,maptmp,comp)

    for _ in range(q):
        l,r,x = ina()
        tmptree.effect(l-1,r,x)
        print(tmptree.folded(0,n)[0])
        

        
















    
    



    


        
        
        


    
        


        


    




















if __name__ == "__main__":
    main()

Submission status: Runtime Error

Solution code:

N, Q = map(int, input().split())
LV = (N-1).bit_length()
N0 = 2**LV
data = [(1, 0)]*(2*N0)
lazy = [None]*(2*N0)

def gindex(l, r):
    L = (l + N0) >> 1; R = (r + N0) >> 1
    lc = 0 if l & 1 else (L & -L).bit_length()
    rc = 0 if r & 1 else (R & -R).bit_length()
    for i in range(LV):
        if rc <= i:
            yield R
        if L < R and lc <= i:
            yield L
        L >>= 1; R >>= 1

def propagates(*ids):
    for i in reversed(ids):
        v = lazy[i-1]
        if v is None:
            continue
        lazy[2*i-1] = lazy[2*i] = data[2*i-1] = data[2*i] = v >> 1
        lazy[i-1] = None

def update(l, r, x):
    *ids, = gindex(l, r)
    propagates(*ids)

    L = N0 + l; R = N0 + r
    v = x
    while L < R:
        if R & 1:
            R -= 1
            lazy[R-1] = data[R-1] = v
        if L & 1:
            lazy[L-1] = data[L-1] = v
            L += 1
        L >>= 1; R >>= 1; v <<= 1
    for i in ids:
        data[i-1] = segfunc(data[2*i-1], data[2*i])

def query(l, r):
    propagates(*gindex(l, r))
    L = N0 + l; R = N0 + r

    s = 0
    while L < R:
        if R & 1:
            R -= 1
            s = segfunc(s, data[R-1])
        if L & 1:
            s = segfunc(s, data[L-1])
            L += 1
        L >>= 1; R >>= 1
    return s

update(0,N,1)
MOD = 998244353
for i in range(Q):
    l, r, d = map(int, input().split())
    update(l-1, r, d)

tt = 1
R = 0
for i in range(N-1, -1, -1):
    c = query(i, i+1)
    R = (R + c*tt) % MOD
    tt = tt*10%MOD
print(R)

Submission status: Runtime Error

Solution code:
import sys
input = sys.stdin.readline

    
class LazySegmentTree():
    def __init__(self, n, op, e, mapping, composition, id):
        self.n = n
        self.op = op
        self.e = e
        self.mapping = mapping
        self.composition = composition
        self.id = id
        self.log = (n - 1).bit_length()
        self.size = 1 << self.log
        self.d = [e] * (2 * self.size)
        self.lz = [id] * (self.size)
 
    def update(self, k):
        self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])
 
    def all_apply(self, k, f):
        self.d[k] = self.mapping(f, self.d[k])
        if k < self.size:
            self.lz[k] = self.composition(f, self.lz[k])
 
    def push(self, k):
        self.all_apply(2 * k, self.lz[k])
        self.all_apply(2 * k + 1, self.lz[k])
        self.lz[k] = self.id
 
    def build(self, arr):
        #assert len(arr) == self.n
        for i, a in enumerate(arr):
            self.d[self.size + i] = a
        for i in range(1, self.size)[::-1]:
            self.update(i)
 
    def set(self, p, x):
        #assert 0 <= p < self.n
        p += self.size
        for i in range(1, self.log + 1)[::-1]:
            self.push(p >> i)
        self.d[p] = x
        for i in range(1, self.log + 1):
            self.update(p >> i)
 
    def get(self, p):
        #assert 0 <= p < self.n
        p += self.size
        for i in range(1, self.log + 1):
            self.push(p >> i)
        return self.d[p]
 
    def prod(self, l, r):
        #assert 0 <= l <= r <= self.n
        if l == r: return self.e
        l += self.size
        r += self.size
        for i in range(1, self.log + 1)[::-1]:
            if ((l >> i) << i) != l: self.push(l >> i)
            if ((r >> i) << i) != r: self.push(r >> i)
        sml = smr = self.e
        while l < r:
            if l & 1:
                sml = self.op(sml, self.d[l])
                l += 1
            if r & 1:
                r -= 1
                smr = self.op(self.d[r], smr)
            l >>= 1
            r >>= 1
        return self.op(sml, smr)
 
    def all_prod(self):
        return self.d[1]
 
    def apply(self, p, f):
        #assert 0 <= p < self.n
        p += self.size
        for i in range(1, self.log + 1)[::-1]:
            self.push(p >> i)
        self.d[p] = self.mapping(f, self.d[p])
        for i in range(1, self.log + 1):
            self.update(p >> i)
 
    def range_apply(self, l, r, f):
        #assert 0 <= l <= r <= self.n
        if l == r: return
        l += self.size
        r += self.size
        for i in range(1, self.log + 1)[::-1]:
            if ((l >> i) << i) != l: self.push(l >> i)
            if ((r >> i) << i) != r: self.push((r - 1) >> i)
        l2 = l
        r2 = r
        while l < r:
            if l & 1:
                self.all_apply(l, f)
                l += 1
            if r & 1:
                r -= 1
                self.all_apply(r, f)
            l >>= 1
            r >>= 1
        l = l2
        r = r2
        for i in range(1, self.log + 1):
            if ((l >> i) << i) != l: self.update(l >> i)
            if ((r >> i) << i) != r: self.update((r - 1) >> i)
 
    def max_right(self, l, g):
        #assert 0 <= l <= self.n
        #assert g(self.e)
        if l == self.n: return self.n
        l += self.size
        for i in range(1, self.log + 1)[::-1]:
            self.push(l >> i)
        sm = self.e
        while True:
            while l % 2 == 0: l >>= 1
            if not g(self.op(sm, self.d[l])):
                while l < self.size:
                    self.push(l)
                    l = 2 * l
                    if g(self.op(sm, self.d[l])):
                        sm = self.op(sm, self.d[l])
                        l += 1
                return l - self.size
            sm = self.op(sm, self.d[l])
            l += 1
            if (l & -l) == l: return self.n
 
    def min_left(self, r, g):
        #assert 0 <= r <= self.n
        #assert g(self.e)
        if r == 0: return 0
        r += self.size
        for i in range(1, self.log + 1)[::-1]:
            self.push((r - 1) >> i)
        sm = self.e
        while True:
            r -= 1
            while r > 1 and r % 2: r >>= 1
            if not g(self.op(self.d[r], sm)):
                while r < self.size:
                    self.push(r)
                    r = 2 * r + 1
                    if g(self.op(self.d[r], sm)):
                        sm = self.op(self.d[r], sm)
                        r -= 1
                return r + 1 - self.size
            sm = self.op(self.d[r], sm)
            if (r & -r) == r: return 0

mod = 998244353
 
def op(x, y):
    xv, xr = divmod(x,1<<31)
    yv, yr = divmod(y,1<<31)
    return ((xv + yv)%mod << 31) + (xr + yr)%mod
def mapping(p, x):
    xv, xr = divmod(x,1<<31)
    if p != -1:
        return ((p*xr%mod) << 31) + xr
    else:
        return x
def composition(p,q):
    if p == -1:
        return q
    return p

n,q = map(int,input().split())
LST = LazySegmentTree(n,op,0,mapping,composition,-1)

def build_exp(n, b):
    res = [0] * (n + 1)
    res[0] = 1
    for i in range(n):
        res[i + 1] = res[i] * b % MOD
    return res
 
exp = build_exp(n-1, 10)

#print(res)
LST.build(exp[::-1])
#print(LST.all_prod()>>31)
for _ in range(q):
    l,r,D = map(int,input().split())
    LST.range_apply(l-1,r,D)
    print((LST.all_prod()>>31)%mod)

Submission status: Runtime Error

Solution code:
import sys
input = sys.stdin.readline

    
class LazySegmentTree():
    def __init__(self, n, op, e, mapping, composition, id):
        self.n = n
        self.op = op
        self.e = e
        self.mapping = mapping
        self.composition = composition
        self.id = id
        self.log = (n - 1).bit_length()
        self.size = 1 << self.log
        self.d = [e] * (2 * self.size)
        self.lz = [id] * (self.size)
 
    def update(self, k):
        self.d[k] = self.op(self.d[2 * k], self.d[2 * k + 1])
 
    def all_apply(self, k, f):
        self.d[k] = self.mapping(f, self.d[k])
        if k < self.size:
            self.lz[k] = self.composition(f, self.lz[k])
 
    def push(self, k):
        self.all_apply(2 * k, self.lz[k])
        self.all_apply(2 * k + 1, self.lz[k])
        self.lz[k] = self.id
 
    def build(self, arr):
        #assert len(arr) == self.n
        for i, a in enumerate(arr):
            self.d[self.size + i] = a
        for i in range(1, self.size)[::-1]:
            self.update(i)
 
    def set(self, p, x):
        #assert 0 <= p < self.n
        p += self.size
        for i in range(1, self.log + 1)[::-1]:
            self.push(p >> i)
        self.d[p] = x
        for i in range(1, self.log + 1):
            self.update(p >> i)
 
    def get(self, p):
        #assert 0 <= p < self.n
        p += self.size
        for i in range(1, self.log + 1):
            self.push(p >> i)
        return self.d[p]
 
    def prod(self, l, r):
        #assert 0 <= l <= r <= self.n
        if l == r: return self.e
        l += self.size
        r += self.size
        for i in range(1, self.log + 1)[::-1]:
            if ((l >> i) << i) != l: self.push(l >> i)
            if ((r >> i) << i) != r: self.push(r >> i)
        sml = smr = self.e
        while l < r:
            if l & 1:
                sml = self.op(sml, self.d[l])
                l += 1
            if r & 1:
                r -= 1
                smr = self.op(self.d[r], smr)
            l >>= 1
            r >>= 1
        return self.op(sml, smr)
 
    def all_prod(self):
        return self.d[1]
 
    def apply(self, p, f):
        #assert 0 <= p < self.n
        p += self.size
        for i in range(1, self.log + 1)[::-1]:
            self.push(p >> i)
        self.d[p] = self.mapping(f, self.d[p])
        for i in range(1, self.log + 1):
            self.update(p >> i)
 
    def range_apply(self, l, r, f):
        #assert 0 <= l <= r <= self.n
        if l == r: return
        l += self.size
        r += self.size
        for i in range(1, self.log + 1)[::-1]:
            if ((l >> i) << i) != l: self.push(l >> i)
            if ((r >> i) << i) != r: self.push((r - 1) >> i)
        l2 = l
        r2 = r
        while l < r:
            if l & 1:
                self.all_apply(l, f)
                l += 1
            if r & 1:
                r -= 1
                self.all_apply(r, f)
            l >>= 1
            r >>= 1
        l = l2
        r = r2
        for i in range(1, self.log + 1):
            if ((l >> i) << i) != l: self.update(l >> i)
            if ((r >> i) << i) != r: self.update((r - 1) >> i)
 
    def max_right(self, l, g):
        #assert 0 <= l <= self.n
        #assert g(self.e)
        if l == self.n: return self.n
        l += self.size
        for i in range(1, self.log + 1)[::-1]:
            self.push(l >> i)
        sm = self.e
        while True:
            while l % 2 == 0: l >>= 1
            if not g(self.op(sm, self.d[l])):
                while l < self.size:
                    self.push(l)
                    l = 2 * l
                    if g(self.op(sm, self.d[l])):
                        sm = self.op(sm, self.d[l])
                        l += 1
                return l - self.size
            sm = self.op(sm, self.d[l])
            l += 1
            if (l & -l) == l: return self.n
 
    def min_left(self, r, g):
        #assert 0 <= r <= self.n
        #assert g(self.e)
        if r == 0: return 0
        r += self.size
        for i in range(1, self.log + 1)[::-1]:
            self.push((r - 1) >> i)
        sm = self.e
        while True:
            r -= 1
            while r > 1 and r % 2: r >>= 1
            if not g(self.op(self.d[r], sm)):
                while r < self.size:
                    self.push(r)
                    r = 2 * r + 1
                    if g(self.op(self.d[r], sm)):
                        sm = self.op(self.d[r], sm)
                        r -= 1
                return r + 1 - self.size
            sm = self.op(self.d[r], sm)
            if (r & -r) == r: return 0

mod = 998244353
 
def op(x, y):
    xv, xr = divmod(x,1<<31)
    yv, yr = divmod(y,1<<31)
    return ((xv + yv) % MOD << 31) + (xr + yr) % MOD


def mapping(p, x):
    if p == -1:
        return x
    dg = x - ((x>>31)<<31)
    return ((p*dg%mod)<<31) + dg
composition = lambda p,q : q if p == -1 else p

n,q = map(int,input().split())
res = [0]*n
LST = LazySegmentTree(n,op,0,mapping,composition,-1)

v = 0
ten = 1
for i in range(n):
    res[i] = (ten<<31) + ten
    ten = ten*10%mod

#print(res)
LST.build(res[::-1])
#print(LST.all_prod()>>31)
for _ in range(q):
    l,r,D = map(int,input().split())
    LST.range_apply(l-1,r,D)
    print((LST.all_prod()>>31)%mod)

Submission status: Runtime Error

Solution code:
import sys
def input(): return sys.stdin.readline().rstrip()

class LazySegmentTree:
  
  __slots__ = ["n", "seg", "x_unit", "m_unit", "f", "g", "h", "lazy"]

  def __init__(self, n, p, x_unit, m_unit, f, g, h):
    self.n = n
    self.seg = p*2
    self.x_unit = x_unit
    self.m_unit = m_unit
    self.f = f
    self.g = g
    self.h = h
    for i in range(self.n-1, 0, -1):
      self.seg[i] = self.f(self.seg[i<<1], self.seg[(i<<1)+1])
    self.lazy = [m_unit] * (self.n * 2)

  def update(self, l, r, x):
    l += self.n
    r += self.n
    ll = l // (l & -l)
    rr = r // (r & -r) - 1
    for shift in range(ll.bit_length()-1, 0, -1):
      i = ll >> shift
      self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
      self.lazy[(i << 1)+1] = self.h(self.lazy[(i << 1)+1], self.lazy[i])
      self.seg[i] = self.g(self.seg[i], self.lazy[i])
      self.lazy[i] = self.m_unit
    for shift in range(rr.bit_length()-1, 0, -1):
      i = rr >> shift
      self.lazy[i << 1] = self.h(self.lazy[i << 1],   self.lazy[i])
      self.lazy[(i << 1)+1] = self.h(self.lazy[(i << 1)+1], self.lazy[i])
      self.seg[i] = self.g(self.seg[i], self.lazy[i])
      self.lazy[i] = self.m_unit
    while l < r:
      if l & 1:
        self.lazy[l] = self.h(self.lazy[l], x)
        l += 1
      if r & 1:
        r -= 1
        self.lazy[r] = self.h(self.lazy[r], x)
      l >>= 1
      r >>= 1
    while ll > 1:
      ll >>= 1
      self.seg[ll] = self.f(self.g(self.seg[ll << 1], self.lazy[ll << 1]), self.g(self.seg[(ll << 1)+1], self.lazy[(ll << 1)+1]))
      self.lazy[ll] = self.m_unit
    while rr > 1:
      rr >>= 1
      self.seg[rr] = self.f(self.g(self.seg[rr << 1], self.lazy[rr << 1]), self.g(self.seg[(rr << 1)+1], self.lazy[(rr << 1)+1]))
      self.lazy[rr] = self.m_unit

  def query(self, l, r):
    l += self.n
    r += self.n
    ll = l // (l & -l)
    rr = r // (r & -r) - 1
    for shift in range(ll.bit_length()-1, 0, -1):
      i = ll >> shift
      self.lazy[i << 1] = self.h(self.lazy[i << 1], self.lazy[i])
      self.lazy[(i << 1)+1] = self.h(self.lazy[(i << 1)+1], self.lazy[i])
      self.seg[i] = self.g(self.seg[i], self.lazy[i])
      self.lazy[i] = self.m_unit
    for shift in range(rr.bit_length()-1, 0, -1):
      i = rr >> shift
      self.lazy[i << 1] = self.h(self.lazy[i << 1],   self.lazy[i])
      self.lazy[(i << 1)+1] = self.h(self.lazy[(i << 1)+1], self.lazy[i])
      self.seg[i] = self.g(self.seg[i], self.lazy[i])
      self.lazy[i] = self.m_unit
    ans_l = ans_r = self.x_unit
    while l < r:
      if l & 1:
        ans_l = self.f(ans_l, self.g(self.seg[l], self.lazy[l]))
        l += 1
      if r & 1:
        r -= 1
        ans_r = self.f(self.g(self.seg[r], self.lazy[r]), ans_r)
      l >>= 1
      r >>= 1
    return self.f(ans_l, ans_r)

mod=998244353
n,q=map(int,input().split())
digit=[1]
for _ in range(num):
  digit.append(digit[-1]*10%mod)
inv9=pow(9,mod-2,mod)
def f(a,b):
  asum,alen=divmod(a,200001)
  bsum,blen=divmod(b,200001)
  return ((digit[blen]*asum+bsum)%mod)*200001+alen+blen
def g(x,y):
  if y is None:
    return x
  _,xlen=divmod(x,200001)
  return ((digit[xlen]-1)*inv9*y%mod)*200001+xlen
def h(x,y):
  if y is None:
    return x
  return y
seg=LazySegmentTree(n,[200002]*n,0,None,f,g,h)
for _ in range(q):
  l,r,d=map(int,input().split())
  seg.update(l-1,r,d)
  print(seg.query(0,n)//200001)

Submission status: Runtime Error

Solution code:
import sys
import os
import numpy as np

def solve(inp):
    MOD = 998244353

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

    e = 0
    id_x = -1

    n = inp[0]
    q = inp[1]
    X = inp[2::3]
    Y = inp[3::3]
    REP = inp[4::3]
    log = bit_length(n - 1)
    size = 1 << log
    d = [e] * (2 * size)
    lz = [id_x] * size


    def op(a, b):
        a1, a2 = a >> 32, a % (1 << 32)
        b1, b2 = b >> 32, b % (1 << 32)
        c1 = (a1 + b1) % MOD
        c2 = (a2 + b2) % MOD
        return (c1 << 32) + c2


    def mapping(x, a):
        if x == -1:
            return a
        a1, a2 = a >> 32, a % (1 << 32)
        c1 = (x * a2) % MOD
        c2 = a2
        return (c1 << 32) + c2


    def composition(x, y):
        if x == -1:
            return y
        return x


    # ----- seg tree設定 ここまで ----- #


    def update(k):
        d[k] = op(d[2 * k], d[2 * k + 1])


    def all_apply(k, f):
        d[k] = mapping(f, d[k])
        if k < size:
            lz[k] = composition(f, lz[k])


    def push(k):
        all_apply(2 * k, lz[k])
        all_apply(2 * k + 1, lz[k])
        lz[k] = id_x


    def build(arr):
        assert len(arr) == n
        for j in range(n):
            d[size + j] = arr[j]
        for j in range(size - 1, 0, -1):
            update(j)


    def set(p, x):
        assert 0 <= p < n
        p += size
        for i in range(1, log + 1)[::-1]:
            push(p >> i)
        d[p] = x
        for i in range(1, log + 1):
            update(p >> i)


    def get(p):
        assert 0 <= p < n
        p += size
        for i in range(1, log + 1):
            push(p >> i)
        return d[p]


    def prod(l, r):
        assert 0 <= l <= r <= n
        if l == r:
            return e
        l += size
        r += size
        for i in range(1, log + 1)[::-1]:
            if ((l >> i) << i) != l:
                push(l >> i)
            if ((r >> i) << i) != r:
                push(r >> i)
        sml = smr = e
        while l < r:
            if l & 1:
                sml = op(sml, d[l])
                l += 1
            if r & 1:
                r -= 1
                smr = op(d[r], smr)
            l >>= 1
            r >>= 1
        return op(sml, smr)


    def all_prod():
        return d[1]


    def apply(p, f):
        assert 0 <= p < n
        p += size
        for i in range(1, log + 1)[::-1]:
            push(p >> i)
        d[p] = mapping(f, d[p])
        for i in range(1, log + 1):
            update(p >> i)


    def range_apply(l, r, f):
        assert 0 <= l <= r <= n
        if l == r:
            return
        l += size
        r += size
        for i in range(log, 0, -1):
            if ((l >> i) << i) != l:
                push(l >> i)
            if ((r >> i) << i) != r:
                push((r - 1) >> i)
        l2 = l
        r2 = r
        while l < r:
            if l & 1:
                all_apply(l, f)
                l += 1
            if r & 1:
                r -= 1
                all_apply(r, f)
            l >>= 1
            r >>= 1
        l = l2
        r = r2
        for i in range(1, log + 1):
            if ((l >> i) << i) != l:
                update(l >> i)
            if ((r >> i) << i) != r:
                update((r - 1) >> i)


    def max_right(l, g):
        assert 0 <= l <= n
        # assert g(e)
        if l == n:
            return n
        l += size
        for i in range(1, log + 1)[::-1]:
            push(l >> i)
        sm = e
        while True:
            while l % 2 == 0:
                l >>= 1
            if not g(op(sm, d[l])):
                while l < size:
                    push(l)
                    l = 2 * l
                    if g(op(sm, d[l])):
                        sm = op(sm, d[l])
                        l += 1
                return l - size
            sm = op(sm, d[l])
            l += 1
            if (l & -l) == l:
                return n


    def min_left(r, g):
        assert 0 <= r <= n
        assert g(e)
        if r == 0:
            return 0
        r += size
        for i in range(1, log + 1)[::-1]:
            push((r - 1) >> i)
        sm = e
        while True:
            r -= 1
            while r > 1 and r % 2:
                r >>= 1
            if not g(op(d[r], sm)):
                while r < size:
                    push(r)
                    r = 2 * r + 1
                    if g(op(d[r], sm)):
                        sm = op(d[r], sm)
                        r -= 1
                return r + 1 - size
            sm = op(d[r], sm)
            if (r & -r) == r:
                return 0

    A = np.zeros(n, dtype=np.int64)
    tmp = 1
    for i in range(n - 1, -1, -1):
        A[i] = (tmp << 32) + tmp
        tmp *= 10
        tmp %= MOD

    build(A)

    ans = np.zeros(q, dtype=np.int64)
    for i in range(q):
        range_apply(X[i] - 1, Y[i], REP[i])
        ans[i] = all_prod() >> 32

    return '\n'.join(map(str, 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(ans)