#include <bits/stdc++.h>

template <class M, class E, class F = std::function<M(M, M)>, class A = std::function<M(M, E)>, class G = std::function<E(E, E)>>
class LazySegmentTree {
private:
  M* data;
  E* lazy;
  F op;
  G cp;
  A act;
  M e;
  E id;
  int sz;

  void propagate(int index) {
    if (lazy[index] == id) return;
    lazy[index << 1] = cp(lazy[index << 1], lazy[index]);
    lazy[(index << 1) | 1] = cp(lazy[(index << 1) | 1], lazy[index]);
    data[index] = act(data[index], lazy[index]);
    lazy[index] = id;
  }

  void propagate_topdown(int index) {
    int h = 0;
    for (int i = 1; i < index; i <<= 1) ++h;
    for (int i = h; i; i--) propagate(index >> i); 
  }

  void recalc(int index) { while (index >>= 1) data[index] = op(act(data[index << 1], lazy[index << 1]), act(data[(index << 1) | 1], lazy[(index << 1) | 1])); }

public:
  LazySegmentTree(int sz, const F& op, const A& act, const G& cp, const M& e, const E& id) : op(op), act(act), cp(cp), e(e), id(id), sz(sz) {
    data = new M[sz << 1];
    lazy = new E[sz << 1];
    for (int i = 0; i < (sz << 1); i++) data[i] = e;
    for (int i = 0; i < (sz << 1); i++) lazy[i] = id;
  }

  void update(int left, int right, const E& x) {
    if (left < 0) left = 0;
    if (right > sz) right = sz;
    left += sz; right += sz;

    propagate_topdown(left);
    propagate_topdown(right - 1);

    for (int l = left, r = right; l < r; l >>= 1, r >>= 1) {
      if (l & 1) {
        lazy[l] = cp(lazy[l], x);
        ++l;
      }
      if (r & 1) {
        --r;
        lazy[r] = cp(lazy[r], x);
      }
    }

    recalc(left);
    recalc(right - 1);
  }

  M query(int left, int right) {
    if (left < 0) left = 0;
    if (right > sz) right = sz;
    left += sz; right += sz;

    propagate_topdown(left);
    propagate_topdown(right - 1);

    M l = e, r = e;

    for (; left < right; left >>= 1, right >>= 1) {
      if (left & 1) {
        l = op(l, act(data[left], lazy[left]));
        ++left;
      }
      if (right & 1) {
        --right;
        r = op(act(data[right], lazy[right]), r);
      }
    }

    return op(l, r);
  }

  ~LazySegmentTree() {
    delete[] data;
    delete[] lazy;
  }
  
  void debug() {
    for (int i = sz; i < sz + sz; i++) {
      std::cout << lazy[i].num << ' ' << lazy[i].d << ' ';
    }
    std::cout << std::endl;
  }
};

const int MOD = 998244353;

using namespace std;

struct M {
  long long num;
  long long d;
  M() : num(0), d(0) {}
  M(long long num, long long d) : num(num), d(d) {}
};

bool operator==(const M& a, const M& b) {
  return a.num == b.num && a.d == b.d;
}

struct E {
  int num;
  long long d;
  E() : num(0), d(MOD) {}
  E(int num) : num(num), d(MOD) {}
  E(int num, long long d) : num(num), d(d) {}
};

bool operator==(const E& f, const E& g) {
  return f.num == g.num && f.d == g.d;
}

int main() {
  int N, Q;
  cin >> N >> Q;
  
  auto op = [](const M& a, const M& b) {
    return M((a.num + b.num) % MOD, (a.d + b.d) % MOD);
  };
  
  auto act = [](const M& x, const E& f) {
    if (f.num == 0 && f.d == MOD) return x;
    else if(f.d == MOD) return M(x.d * f.num % MOD, x.d);
    else return M(f.d * f.num % MOD, f.d);
  };
  
  auto cp = [](const E& f, const E& g) {
    if (g.num == 0 && g.d == MOD) return f;
    else if (g.d == MOD) return E(g.num, f.d);
    else return g;
  };
    
  LazySegmentTree<M, E, decltype(op), decltype(act), decltype(cp)> segTree(N, op, act, cp, M(0, 0), E(0, MOD));
  
  segTree.update(N - 1, N, E(1, 1));
  for (int i = N - 1; i > 0; i--) {
    auto s = segTree.query(i, i + 1);
    segTree.update(i - 1, i, E(0, s.d * 10 % MOD));
    segTree.update(i - 1, i, E(1));
  }
  
  while (Q--) {
    int L, R, D;
    cin >> L >> R >> D;
    segTree.update(L - 1, R, D);
    cout << segTree.query(0, N).num << endl;
  }
  
  return 0;
}

Measured memory_bytes: 15680