// #define _GLIBCXX_DEBUG
#define _USE_MATH_DEFINES
#include <bits/stdc++.h>
using namespace std;
using ll = long long; using ull = unsigned long long;
using pii = pair<int, int>; using vi = vector<int>; using vvi = vector<vi>; using puu = pair<uint, uint>; using vu = vector<uint>; using vvu = vector<vu>;
using pll = pair<ll, ll>; using vl = vector<ll>; using vvl = vector<vl>; // using pulul = pair<ull, ull>; using vul = vector<ull>; using vvul = vectro<vul>;
using vb = vector<bool>; using vvb = vector<vb>;
#define rep0(TMS) for (int CNT = 0; CNT < (int)(TMS); CNT++)
#define rep(CNT, GOAL) for (int CNT = 0; CNT < (int)(GOAL); CNT++)
#define rep2(CNT, START, GOAL) for (int CNT = (int)(START); CNT < (int)(GOAL); CNT++)
#define rep3(CNT, START, GOAL) for (int CNT = (int)(START); CNT > (int)(GOAL); CNT--)
#define all(CONT) begin(CONT), end(CONT)
template <typename T> bool chmax(T &a, const T &b) { if (a < b) { a = b; return true; } return false; }
template <typename T> bool chmin(T &a, const T &b) { if (a > b) { a = b; return true; } return false; }
void prec(const int &DIG) { cout << fixed << setprecision(DIG); cerr << fixed << setprecision(DIG); }
template <typename T> void CERR(const T &ELEM) { cerr << ELEM; }
#define dbl(OBJ) cerr << #OBJ << ": "; CERR(OBJ); cerr << "\n"
template <typename T, typename ...Ts> void CERR(const T &FIRST, const Ts &...REST) { CERR(FIRST); cerr << ", "; CERR(REST...); }
#define dbs(...) cerr << "(" << #__VA_ARGS__ << "): ("; CERR(__VA_ARGS__); cerr << ")\n"
#define itrep(ITR, CONT) for (auto ITR = begin(CONT); ITR != end(CONT); ITR++)
template <typename T> void CERR(const vector<T> &VEC) { cerr << "{ "; itrep(ITR, VEC) { CERR(*ITR); cerr << ", "; } cerr << "}"; }
#define YN(FLG) cout << (FLG ? "YES" : "NO") << "\n"
#define Yn(FLG) cout << (FLG ? "Yes" : "No") << "\n"
#define yn(FLG) cout << (FLG ? "yes" : "no") << "\n"

#include <atcoder/all>

using namespace atcoder;
using mint = modint998244353;

int N, Q;
vector<mint> mp, mpR1;

struct S { mint a; int l, r; };
const S E = { 0, 0, 0 };
bool operator==(S x, S y) { return x.a == y.a and x.l == y.l and x.r == y.r; }

S op(S x, S y) {
	if (x == E) return y;
	else if (y == E) return x;
	else {
		assert(x.r == y.l);
		mint na = x.a * mp[y.r - y.l] + y.a;
		return S { na, x.l, y.r };
	}
}
S e() { return E; }

using F = mint;
const F ID = 0;

S mapping(F f, S x) {
	if (f == ID) return x;
	else return S{ f * mpR1[x.r - x.l], x.l, x.r };
}
F composition(F f, F g) {
	if (f == ID) return g;
	else return f;
}
F id() { return ID; }

void show(lazy_segtree<S, op, e, F, mapping, composition, id> &seg) {
	rep(i, N) cout << seg.get(i).a.val();
	cout << endl;
}
void show_all(lazy_segtree<S, op, e, F, mapping, composition, id> &seg) {
	rep(i, N + 1) {
		rep2(j, i, N + 1) {
			cout << "[" << i << "," << j << "): ";
			cout << seg.prod(i, j).a.val() << endl;
		}
	}
}

void init() {
	mp = vector<mint>(N + 1); mp[0] = 1; // 10^i
	mpR1 = vector<mint>(N + 1); mpR1[0] = 0; // (10^i-1)/9
	rep(i, N) {
		mp[i + 1] = 10 * mp[i];
		mpR1[i + 1] = 10 * mpR1[i] + 1;
	}
}

int main() {
	cin >> N >> Q;
	init();
	lazy_segtree<S, op, e, F, mapping, composition, id> seg(N);
	rep(i, N) {
		seg.set(i, S{ 1, i, i + 1 });
		// cout << i << endl;
		// S s = seg.get(i);
		// cout << s.a.val() << " " << s.l << " " << s.r << endl;
	}
	// show(seg); show_all(seg);
	rep(i, Q) {
		int L, R, D; cin >> L >> R >> D;
		L--; R--;
		seg.apply(L, R + 1, D);
		// show(seg); show_all(seg);
		cout << seg.all_prod().a.val() << endl;
	}
}

Measured memory_bytes: 14388