#include <bits/stdc++.h>
using namespace std;
using lint         = long long;
constexpr lint inf = 1LL << 60;
constexpr lint mod = 998244353;
// constexpr lint mod = 1000000007;

template <lint mod>
struct modint {
    lint v;
    constexpr modint(lint t = 0) noexcept {
        v = t % mod;
        if (v < 0)
            v += mod;
    }
    constexpr modint pow(lint k) const {
        modint res(1), tmp(v);
        while (k) {
            if (k & 1)
                res *= tmp;
            tmp *= tmp;
            k >>= 1;
        }
        return res;
    }
    static modint add_identity() { return modint(0); }
    static modint mul_identity() { return modint(1); }
    constexpr modint inv() const { return pow(mod - 2); }

    constexpr modint &operator+=(const modint a) noexcept {
        v += a.v;
        if (v >= mod)
            v -= mod;
        return *this;
    }
    constexpr modint &operator-=(const modint a) noexcept {
        v += mod - a.v;
        if (v >= mod)
            v -= mod;
        return *this;
    }
    constexpr modint &operator*=(const modint a) noexcept {
        v = v * a.v % mod;
        return *this;
    }
    constexpr modint &operator/=(const modint a) noexcept { return (*this) *= a.inv(); }

    constexpr modint operator+(const modint a) const noexcept { return modint(v) += a; };
    constexpr modint operator-(const modint a) const noexcept { return modint(v) -= a; };
    constexpr modint operator*(const modint a) const noexcept { return modint(v) *= a; };
    constexpr modint operator/(const modint a) const noexcept { return modint(v) /= a; };
    constexpr modint operator-() const noexcept { return v ? modint(mod - v) : modint(v); }

    constexpr bool operator==(const modint a) const noexcept { return v == a.v; }
    constexpr bool operator!=(const modint a) const noexcept { return v != a.v; }
    constexpr bool operator<(const modint a) const noexcept { return v < a.v; }
};
using mint = modint<mod>;
ostream &operator<<(ostream &os, mint m) { return os << m.v; }

template <typename T = lint>
struct SegmentTreeLazy {
  private:
    using F = function<T(T, T, lint)>;
    int n;
    vector<T> node, lazy;
    vector<bool> lazyFlag;
    F func;
    T unit;
    vector<lint> sizes, ssum;
    vector<mint> nines;

  public:
    SegmentTreeLazy(int sz, F func, T unit) : func(func), unit(unit) {
        n = 1;
        while (n < sz)
            n *= 2;
        node.assign(2 * n - 1, unit);
        lazy.assign(2 * n - 1, unit);
        lazyFlag.resize(2 * n - 1, false);
    }
    SegmentTreeLazy(vector<T> v, F func, T unit) : func(func), unit(unit) {
        int sz = int(v.size());
        n      = 1;
        while (n < sz)
            n *= 2;
        nines.resize(n + 10);
        for (int i = 0; i < n + 10; ++i) {
            nines[i] = (mint(10).pow(i) - 1) / 9;
        }
        node.resize(2 * n - 1, unit);
        lazy.resize(2 * n - 1, unit);
        sizes.resize(2 * n - 1, 0);
        for (int i = 0; i < n - 1 + sz; ++i) {
            sizes[i] = 1;
        }
        ssum.resize(n, 0);
        for (int i = 0; i < sz; ++i) {
            ssum[i] = 1;
        }
        for (int i = 1; i < n; ++i) {
            ssum[i] += ssum[i - 1];
        }
        lazyFlag.resize(2 * n - 1, false);

        for (int i = 0; i < sz; i++)
            node[i + n - 1] = v[i];
        for (int i = n - 2; i >= 0; i--) {
            sizes[i] = sizes[i * 2 + 1] + sizes[i * 2 + 2];
            node[i]  = func(node[i * 2 + 1], node[i * 2 + 2], sizes[i * 2 + 2]);
        }
    }
    void lazyEvaluate(int k, int l, int r) {
        if (lazyFlag[k]) {
            node[k] = nines[sizes[k]] * lazy[k];
            if (r - l > 1) {
                lazy[k * 2 + 1] = lazy[k * 2 + 2] = lazy[k];
                lazyFlag[k * 2 + 1] = lazyFlag[k * 2 + 2] = true;
            }
            lazyFlag[k] = false;
            // lazy[k]     = 0;
        }
    }
    // replace nodes with x in [a, b)
    void update(int a, int b, T x, int k = 0, int l = 0, int r = -1) {
        if (r < 0)
            r = n;
        lazyEvaluate(k, l, r);
        if (b <= l || r <= a)
            return;
        if (a <= l && r <= b) {
            // mint nv     = (mint(10).pow(sizes[k]) - 1) / 9 * x;
            lazy[k]     = x;
            lazyFlag[k] = true;
            lazyEvaluate(k, l, r);
        } else {
            const int mid = (l + r) / 2;
            update(a, b, x, 2 * k + 1, l, mid);
            update(a, b, x, 2 * k + 2, mid, r);
            node[k] = func(node[2 * k + 1], node[2 * k + 2], sizes[2 * k + 1]);
        }
    }
    // get func() in [a, b)
    T query(int a, int b, int k = 0, int l = 0, int r = -1) {
        if (r < 0)
            r = n;
        lazyEvaluate(k, l, r);
        if (b <= l || r <= a)
            return unit;
        if (a <= l && r <= b)
            return node[k];
        T vl    = query(a, b, 2 * k + 1, l, (l + r) / 2);
        T vr    = query(a, b, 2 * k + 2, (l + r) / 2, r);
        lint nr = ssum[r - 1] - ssum[max(0, (l + r) / 2 - 1)];
        return func(vl, vr, nr);
    }
};

int main() {
    cin.tie(nullptr);
    ios::sync_with_stdio(false);
    lint n, q;
    cin >> n >> q;
    vector<mint> init(n, 1);
    vector<mint> tens(200010, 0);
    for (int i = 0; i < 200010; ++i) {
        tens[i] = mint(10).pow(i);
    }
    auto f = [&](mint l, mint r, lint nr) {
        if (nr == 0)
            return l;
        else
            return tens[nr] * l + r;
    };
    const mint unit = 0;
    SegmentTreeLazy<mint> seg(init, f, unit);
    for (int i = 0; i < q; ++i) {
        int l, r, d;
        cin >> l >> r >> d;
        l--, r--;
        seg.update(l, r + 1, d);
        cout << seg.query(0, n) << endl;
    }
    return 0;
}

Measured memory_bytes: 24336