#pragma region Header
#ifdef DEBUG
#include "debug.hpp"
#else
#define debug(...)
#define IFD(...)
#ifndef NDEBUG
#define NDEBUG
#endif
#endif
#include <utility>
#include <cstdint>
#include <cmath>
#include <cassert>
#include <vector>
#include <array>
#include <deque>
#include <queue>
#include <stack>
#include <tuple>
#include <set>
#include <map>
#include <unordered_map>
#include <bitset>
#include <string>
#include <functional>
#include <algorithm>
#include <numeric>
#include <stdexcept>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <boost/hana/functional/fix.hpp>
using boost::hana::fix;
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using u32 = uint32_t;
using u64 = uint64_t;
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repd(i, n) for (int i = (n)-1; i >= 0; --i)
#define FOR(i, a, b) for (int i = (a); i <= (b); ++i)
#define FORD(i, b, a) for (int i = (b); i >= (a); --i)
template <typename T>
int SZ(T const &x)
{
    return static_cast<int>(x.size());
}
template <class T>
bool chmax(T &a, T const &b)
{
    if (a < b)
    {
        a = b;
        return true;
    }
    return false;
}
template <class T>
bool chmin(T &a, T const &b)
{
    if (b < a)
    {
        a = b;
        return true;
    }
    return false;
}
#pragma endregion
#include <atcoder/lazysegtree>
using namespace atcoder;

template <u32 p>
struct modint
{
private:
    u32 data; // in [0,p)

    constexpr static inline i64 p_i64 = static_cast<i64>(p);

public:
    constexpr modint() noexcept
        : data(0) {}

    constexpr modint(i64 const x) noexcept
        : data(static_cast<u32>((x % p_i64 >= 0) ? x % p_i64 : x % p_i64 + p_i64)) {}

    constexpr modint(u32 const x, bool const) noexcept
        : data(x) {}

    // convert to u32
    constexpr u32 const &val() const noexcept
    {
        return data;
    }

    constexpr modint &operator+=(modint const x) noexcept
    {
        data += x.data;
        if (data >= p)
        {
            data -= p;
        }
        return *this;
    }

    constexpr modint &operator-=(modint const x) noexcept
    {
        if (data < x.data)
        {
            data += p;
        }
        data -= x.data;
        return *this;
    }

    constexpr modint &operator*=(modint const x) noexcept
    {
        data = static_cast<u32>(static_cast<u64>(data) * x.data % p);
        return *this;
    }

    constexpr modint &operator/=(modint x)
    {
        if (x.data == 0)
        {
            throw domain_error("Division by modint zero");
        }
        u32 exp = p - 2;
        // (*this) * (x ** exp) : invariant
        while (exp > 0)
        {
            if (exp & 1)
            {
                *this *= x;
            }
            x *= x;
            exp /= 2;
        }
        return *this;
    }

    constexpr modint &operator++() noexcept
    {
        return *this += modint(1, true);
    }

    constexpr modint operator++(int) noexcept
    {
        modint const ret(*this);
        ++(*this);
        return ret;
    }

    constexpr modint &operator--() noexcept
    {
        return *this -= modint(1, true);
    }

    constexpr modint operator--(int) noexcept
    {
        modint const ret(*this);
        --(*this);
        return ret;
    }

    constexpr modint operator-() const noexcept
    {
        return modint(0, true) -= *this;
    }

    constexpr modint operator+(modint const x) const noexcept
    {
        return modint(*this) += x;
    }

    constexpr modint operator-(modint const x) const noexcept
    {
        return modint(*this) -= x;
    }

    constexpr modint operator*(modint const x) const noexcept
    {
        return modint(*this) *= x;
    }

    constexpr modint operator/(modint const x) const
    {
        return modint(*this) /= x;
    }

    // x >= 0 のときべき乗を計算
    constexpr modint pow(u64 exp) const noexcept
    {
        modint ret(1, true), base(*this);
        // ret * (base ** exp) : invariant, == (*this) ** x
        while (exp > 0)
        {
            if (exp & 1)
            {
                ret *= base;
            }
            base *= base;
            exp /= 2;
        }
        return ret;
    }

    constexpr modint inv() const noexcept
    {
        return modint(1, true) /= *this;
    }

    constexpr bool operator==(modint const x) const noexcept
    {
        return data == x.data;
    }
};

constexpr u32 mod = 998'244'353;
using mint = modint<mod>;

constexpr int nbig = 2'00'000 + 1;

struct S
{
    mint x;
    int len;
};

vector<mint> tens(nbig), ones(nbig);

auto op(S a, S b) -> S
{
    return S{tens[b.len] * a.x + b.x, a.len + b.len};
}
auto e() -> S
{
    return S{mint{0}, 0};
}
auto mapping(int u, S a) -> S
{
    return u == -1 ? a : S{ones[a.len] * mint{u}, a.len};
}
auto composition(int u, int v) -> int
{
    return u == -1 ? v : u;
}
auto id() -> int { return -1; }

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout << fixed << setprecision(15);

    int n, q;
    cin >> n >> q;

    mint powoften{1};
    rep(i, nbig)
    {
        tens[i] = powoften;
        powoften *= 10;
    }
    ones[0] = 0;
    rep(i, nbig - 1)
    {
        ones[i + 1] = ones[i] + tens[i];
    }

    vector<S> initializing_vector(n, S{mint{1}, 1});
    lazy_segtree<S, op, e, int, mapping, composition, id> seg(initializing_vector);
    mint ans;

    // debug(seg.prod(0, n).x.val());
    // IFD(seg.apply(1, 3, 3);)
    // debug(seg.prod(0, n).x.val());
    rep(i, q)
    {
        int l, r, d;
        cin >> l >> r >> d;
        --l;
        seg.apply(l, r, d);
        ans = seg.prod(0, n).x;
        cout << ans.val() << '\n';
    }

    return 0;
}


Measured memory_bytes: 11364