#include <bits/stdc++.h>
#include <variant>
#define FOR(i,k,n)  for(int i = (k);i < (n);++i)
#define REP(i,n)    FOR(i,0,n)
#define ALL(x) begin(x),end(x)

using namespace std;
using namespace std::string_literals;
using ll = int64_t;
using vecint = vector<int>;
using vecll = vector<ll>;

constexpr ll MOD = 998244353;

struct Data {
  int num;
  int len;
  Data() : num(0), len(1) {;}
  Data(int n, int l) : num(n), len(l) {;}
};

const Data identity = Data(0, 0);

ll powm(ll x, ll i) {
  if (i == 0) return 1;
  if (i % 2 == 1) return powm(x, i-1) * x % MOD;
  ll h = powm(x, i/2);
  return h * h % MOD;
}

inline Data Merge(Data left, Data right) {
  //cerr<<left.num<<" "<<left.len<<" "<<right.num<<" "<<right.len<<endl;
  ll pm = powm(10, right.len);
  return Data((left.num * pm % MOD + right.num) % MOD, left.len + right.len);
}
inline Data Set(Data lazy, Data val, int num) {
  val.len = num;
  return val;
}
inline Data Eval(Data data, Data lazy, int num) {
  ll pm = 10;
  ll sum = lazy.num;
  int len = num;
  //cerr << num << " " << sum << " ";
  for (; num > 1; num >>= 1) {
    sum += sum * pm % MOD;
    sum %= MOD;
    pm *= pm;
    pm %= MOD;
  }
  //cerr << "S=" << sum << endl;
  return Data(sum, len);
}

class SegmentTreeLazy {
  int n;
  vector<Data> data, lazy;
  vector<bool> flag;
  void lazyset(int node, Data val, int num) {
    if (flag[node]) lazy[node] = Set(lazy[node], val, num);
    else lazy[node] = val;
    flag[node] = true;
  }
  void evaluate(int node, int num) {
    if (!flag[node]) return;
    Data val = lazy[node];
    data[node] = Eval(data[node], val, num); flag[node] = false;
    if (node < n) return;
    lazyset((node-n)*2+0, val, num/2); lazyset((node-n)*2+1, val, num/2);
  }
  void update_sub(int fr, int to, int node, int la, int ra, Data val) {
    //cerr << fr << " " << to << " " << node << " " << la << " " << ra << endl;
    if (ra <= fr || to <= la) { evaluate(node, ra - la); return; }
    if (fr <= la && ra <= to) {
      lazyset(node, val, ra - la); evaluate(node, ra - la); return;
    }
    evaluate(node, ra - la);
    int lpos = (node-n)*2+0, rpos = (node-n)*2+1;
    update_sub(fr, to, lpos, la, (la+ra)/2, val);
    update_sub(fr, to, rpos, (la+ra)/2, ra, val);
    data[node] = Merge(data[lpos], data[rpos]);
  }
  Data query_sub(int fr, int to, int node, int la, int ra) {
    if (ra<=fr || to<=la) return identity;
    if (fr<=la && ra<=to) { evaluate(node, ra - la); return data[node]; }
    evaluate(node, ra - la);
    Data l = query_sub(fr, to, (node-n)*2+0, la, (la+ra)/2);
    Data r = query_sub(fr, to, (node-n)*2+1, (la+ra)/2, ra);
    return Merge(l, r);
  }
public:
  SegmentTreeLazy(int N) {
    for (n = 1; n < N; n *= 2);
    data.resize(n * 2), lazy.resize(n * 2);
    flag.assign(n * 2, false);
    REP(i,n*2) flag[i] = false;
  }
  void update(int fr, int to, Data val) { update_sub(fr, to, 2*n-2, 0, n, val); }
  Data query(int fr, int to) { return query_sub(fr, to, 2*n-2, 0, n); }
};

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  int n,q;
  cin>>n>>q;
  SegmentTreeLazy st(n);
  st.update(0, n, Data(1, 1));
  //cout << st.query(0, n).num << "\n";
  REP(i,q) {
    int l,r,d;
    cin>>l>>r>>d;
    --l;
    st.update(l, r, Data(d,1));
    cout << st.query(0, n).num << "\n";
  }
  
  return 0;
}


Measured memory_bytes: 11400