macro_rules! read_line_to_tuple {
    ( $( $t:ty ),* ) => {{
        let mut input = String::new();
        std::io::stdin().read_line(&mut input).unwrap();
        let mut iter = input.split_whitespace();
        ( $( iter.next().unwrap().parse::<$t>().unwrap() ),* )
    }};
}

trait Monoid<T, F> {
    fn op(&self, v1: T, v2: T) -> T;
    fn e(&self) -> T;
    fn mapping(&self, f: F, v: T) -> T;
    fn composition(&self, f1: F, f2: F) -> F;
    fn id(&self) -> F;
}

struct LazySegmentTree<T, F, M> {
    n: usize,
    len: usize,
    height: usize,
    monoid: M,
    node: Vec<T>,
    lazy: Vec<F>,
}

impl<T, F, M> LazySegmentTree<T, F, M>
    where
        T: Clone + Copy,
        F: Clone + Copy,
        M: Monoid<T, F>,
{
    fn new(n: usize, monoid: M) -> LazySegmentTree<T, F, M> {
        let (mut len, mut height) = (1, 1);
        while len < n {
            len *= 2;
            height += 1;
        }
        let node = vec![monoid.e(); 2 * len];
        let lazy = vec![monoid.id(); 2 * len];
        LazySegmentTree {
            n,
            len,
            height,
            monoid,
            node,
            lazy,
        }
    }

    fn from(v: Vec<T>, monoid: M) -> LazySegmentTree<T, F, M> {
        let mut lst = LazySegmentTree::new(v.len(), monoid);
        for i in 0..v.len() { lst.node[i + lst.len] = v[i]; }
        for i in (1..lst.len).rev() {
            lst.update(i);
        }
        lst
    }

    fn update(&mut self, k: usize) {
        self.node[k] = self.monoid.op(self.node[2 * k], self.node[2 * k + 1]);
    }

    fn all_apply(&mut self, k: usize, f: F) {
        self.node[k] = self.monoid.mapping(f, self.node[k]);
        if self.len <= k { return; }
        self.lazy[k] = self.monoid.composition(f, self.lazy[k]);
    }

    fn push(&mut self, k: usize) {
        self.all_apply(2 * k, self.lazy[k]);
        self.all_apply(2* k + 1, self.lazy[k]);
        self.lazy[k] = self.monoid.id();
    }

    fn _set(&mut self, mut p: usize, x: T) {
        assert!(p < self.n);
        p += self.len;
        for i in (1..self.height).rev() { self.push(p >> i); }
        self.node[p] = x;
        for i in 1..self.height { self.update(p >> i); }
    }

    fn prod(&mut self, mut l: usize, mut r: usize) -> T {
        assert!(l <= r && r <= self.n);
        if l == r { return self.monoid.e(); }

        l += self.len;
        r += self.len;

        for i in (1..self.height).rev() {
            if ((l >> i) << i) != l { self.push(l >> i); }
            if ((r >> i) << i) != r { self.push(r >> i); }
        }

        let (mut sml, mut smr) = (self.monoid.e(), self.monoid.e());
        while l < r {
            if l & 1 != 0 {
                sml = self.monoid.op(sml, self.node[l]);
                l += 1;
            }
            if r & 1 != 0 {
                r -= 1;
                smr = self.monoid.op(self.node[r], smr);
            }
            l >>= 1;
            r >>= 1;
        }

        self.monoid.op(sml, smr)
    }

    fn apply(&mut self, mut l: usize, mut r: usize, f: F) {
        assert!(l <= r && r <= self.n);
        if l == r { return; }

        l += self.len;
        r += self.len;

        for i in (1..self.height).rev() {
            if ((l >> i) << i) != l { self.push(l >> i); }
            if ((r >> i) << i) != r { self.push((r - 1) >> i); }
        }

        {
            let (l2, r2) = (l, r);
            while l < r {
                if (l & 1) != 0 {
                    self.all_apply(l, f);
                    l += 1;
                }
                if (r & 1) != 0 {
                    r -= 1;
                    self.all_apply(r, f);
                }
                l >>= 1;
                r >>= 1;
            }
            l = l2;
            r = r2;
        }

        for i in 1..self.height {
            if ((l >> i) << i) != l { self.update(l >> i); }
            if ((r >> i) << i) != r { self.update((r - 1) >> i); }
        }
    }

    fn _max_right<G: Fn(T) -> bool>(&mut self, mut l: usize, g: G) -> usize {
        assert!(l <= self.n);
        assert!(g(self.monoid.e()));
        if l == self.n { return self.n; }
        l += self.len;
        for i in (1..self.height).rev() { self.push(l >> i); }
        let mut sm = self.monoid.e();
        while {
            while l % 2 == 0 { l >>= 1; }
            if !g(self.monoid.op(sm, self.node[l])) {
                while l < self.len {
                    self.push(l);
                    l = 2 * l;
                    if g(self.monoid.op(sm, self.node[l])) {
                        sm = self.monoid.op(sm, self.node[l]);
                        l += 1;
                    }
                }
                return l - self.len;
            }
            sm = self.monoid.op(sm, self.node[l]);
            l += 1;
            (l & (!l + 1)) != l
        } {}
        self.n
    }

    fn _min_left<G: Fn(T) -> bool>(&mut self, mut r: usize, g: G) -> usize {
        assert!(r <= self.n);
        assert!(g(self.monoid.e()));
        if r == 0 { return 0; }
        r += self.len;
        for i in (1..self.height).rev() { self.push((r - 1) >> i); }
        let mut sm = self.monoid.e();
        while {
            r -= 1;
            while r > 1 && r % 2 != 0 { r >>= 1; }
            if !g(self.monoid.op(self.node[r], sm)) {
                while r < self.len {
                    self.push(r);
                    r = 2 * r + 1;
                    if g(self.monoid.op(self.node[r], sm)) {
                        sm = self.monoid.op(self.node[r], sm);
                        r -= 1;
                    }
                }
                return r + 1 - self.len;
            }
            sm = self.monoid.op(self.node[r], sm);
            (r & (!r + 1)) != r
        } {}
        0
    }
}

const MOD: i64 = 998_244_353;

#[derive(Clone, Copy)]
struct T { len: usize, val: i64 }

type F = i64;

struct S {
    ten: Vec<i64>,
    one: Vec<i64>,
}

impl S {
    fn new(n: usize) -> S {
        let mut ten = vec![0; n + 1];
        ten[0] = 1;
        for i in 1..=n {
            ten[i] = ten[i - 1] * 10 % MOD;
        }
        let mut one = vec![0; n + 1];
        for i in 1..=n {
            one[i] = (one[i - 1] * 10 + 1) % MOD;
        }
        S { ten, one }
    }
}

impl Monoid<T, F> for S {
    fn op(&self, v1: T, v2: T) -> T {
        let len = v1.len + v2.len;
        let val = (v1.val * self.ten[v2.len] + v2.val) % MOD;
        T { len, val }
    }
    
    fn e(&self) -> T {
        T { len: 0, val: 0 }
    }
    
    fn mapping(&self, f: F, v: T) -> T {
        if f == 0 { return v; }
        let len = v.len;
        let val = self.one[v.len] * f % MOD;
        T { len, val }
    }
    
    fn composition(&self, f1: F, f2: F) -> F {
        if f1 == 0 { f2 } else { f1 }
    }
    
    fn id(&self) -> F {
        0
    }    
}

fn main() {
    let (n, q) = read_line_to_tuple!(usize, usize);

    let v = vec![T { len: 1, val: 1 }; n];
    let s = S::new(n);
    let mut lst = LazySegmentTree::from(v, s);
    for _ in 0..q {
        let (l, r, d) = {
            let (l, r, d) = read_line_to_tuple!(usize, usize, i64);
            (l - 1, r, d)
        };

        lst.apply(l, r, d);
        println!("{}", lst.prod(0, n).val);
    }
}


Measured memory_bytes: 16588