#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
string to_string(string s) { return '"' + s + '"'; }
string to_string(const char* s) { return to_string(string(s)); }
string to_string(bool b) { return to_string(int(b)); }
string to_string(char b) { return "'" + string(1, b) + "'"; }
template <typename A, typename B>
string to_string(pair<A, B> p) { return "(" + to_string(p.first) + ", " + to_string(p.second) + ")"; }
template <typename A>
string to_string(A v) {
	string res = "{";
	for (const auto& x : v) res += (res == "{" ? "" : ", ") + to_string(x);
	return res + "}";
}
void debug() { cerr << endl; }
template <typename Head, typename... Tail>
void debug(Head H, Tail... T) {
	cerr << " " << to_string(H);
	debug(T...);
}
#define db(...) cerr << "[" << #__VA_ARGS__ << "]:", debug(__VA_ARGS__)
#else
#define db(...) 42
#endif
typedef long long ll;
typedef long double ld;
const int MOD = 998244353;
struct Mint {
	int val;
	Mint() { val = 0; }
	Mint(const ll& x) {
		val = (-MOD <= x && x < MOD) ? x : x % MOD;
		if (val < 0) val += MOD;
	}
	template <typename U>
	explicit operator U() const { return (U)val; }
	friend bool operator==(const Mint& a, const Mint& b) { return a.val == b.val; }
	friend bool operator!=(const Mint& a, const Mint& b) { return !(a == b); }
	friend bool operator<(const Mint& a, const Mint& b) { return a.val < b.val; }
	Mint& operator+=(const Mint& m) { if ((val += m.val) >= MOD) val -= MOD; return *this; }
	Mint& operator-=(const Mint& m) { if ((val -= m.val) < 0) val += MOD; return *this; }
	Mint& operator*=(const Mint& m) { val = (ll)val * m.val % MOD; return *this; }
	friend Mint modex(Mint a, ll p) {
		assert(p >= 0);
		Mint ans = 1;
		for (; p; p >>= 1, a *= a) if (p & 1) ans *= a;
		return ans;
	}
	Mint& operator/=(const Mint& m) { return *this *= modex(m, MOD - 2); }
	Mint& operator++() { return *this += 1; }
	Mint& operator--() { return *this -= 1; }
	Mint operator++(int) { Mint result(*this); *this += 1; return result; }
	Mint operator--(int) { Mint result(*this); *this -= 1; return result; }
	Mint operator-() const { return Mint(-val); }
	friend Mint operator+(Mint a, const Mint& b) { return a += b; }
	friend Mint operator-(Mint a, const Mint& b) { return a -= b; }
	friend Mint operator*(Mint a, const Mint& b) { return a *= b; }
	friend Mint operator/(Mint a, const Mint& b) { return a /= b; }
	friend ostream& operator<<(ostream& os, const Mint& x) { return os << x.val; }
};
const int MAX = 300005;
Mint p10[MAX], sames[10][MAX];
struct SegTree {
	struct Node {
		Mint x = 1; // Set default value here
		int len = 1;
		int prop = 0;
		// Used for updates and propagation.
		void apply(int s, int e, int v) {
			x = sames[v][e - s + 1];
			prop = v;
		}
	};
	inline Node combine(const Node& a, const Node& b) {
		Node res;
		res.x = a.x * p10[b.len] + b.x;
		res.len = a.len + b.len;
		return res;
	}
	inline void push(int sn, int s, int e) {
		if (tree[sn].prop) {
			int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
			tree[lsn].apply(s, m, tree[sn].prop);
			tree[rsn].apply(m + 1, e, tree[sn].prop);
			tree[sn].prop = 0;
		}
	}
	int start, end;
	vector<Node> tree;
	void build(int sn, int s, int e) {
		if (s == e) {
			// initialize here, possibly.
			return;
		}
		int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
		build(lsn, s, m);
		build(rsn, m + 1, e);
		tree[sn] = combine(tree[lsn], tree[rsn]);
	}
	template <typename T>
	void build(int sn, int s, int e, const vector<T>& v) {
		if (s == e) {
			tree[sn].x = v[s];
			return;
		}
		int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
		build(lsn, s, m, v);
		build(rsn, m + 1, e, v);
		tree[sn] = combine(tree[lsn], tree[rsn]);
	}
	template <typename... T>
	void update(int sn, int s, int e, int qs, int qe, const T&... v) {
		if (qs <= s && e <= qe) {
			tree[sn].apply(s, e, v...);
			return;
		}
		int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
		push(sn, s, e);
		if (qs <= m) update(lsn, s, m, qs, qe, v...);
		if (qe > m) update(rsn, m + 1, e, qs, qe, v...);
		tree[sn] = combine(tree[lsn], tree[rsn]);
	}
	Node query(int sn, int s, int e, int qs, int qe) {
		if (qs <= s && e <= qe) return tree[sn];
		int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
		push(sn, s, e);
		if (qe <= m) return query(lsn, s, m, qs, qe);
		if (qs > m) return query(rsn, m + 1, e, qs, qe);
		return combine(query(lsn, s, m, qs, qe), query(rsn, m + 1, e, qs, qe));
	}
	void query(int sn, int s, int e, int qs, int qe, const function<void(Node&, int, int)>& f) {
		if (qs <= s && e <= qe) return f(tree[sn], s, e);
		int m = (s + e) >> 1, lsn = sn * 2, rsn = sn * 2 + 1;
		push(sn, s, e);
		if (qs <= m) query(lsn, s, m, qs, qe, f);
		if (qe > m) query(rsn, m + 1, e, qs, qe, f);
	}
	SegTree(int n) : SegTree(0, n - 1) {}
	SegTree(int _start, int _end) : start(_start), end(_end) {
		int n = end - start + 1;
		int maxs = n == 1 ? 2 : 1 << (33 - __builtin_clz(n - 1));
		tree.resize(maxs);
		build(1, start, end);
	}
	template <typename T>
	SegTree(const vector<T>& v) {
		int n = v.size();
		int maxs = n == 1 ? 2 : 1 << (33 - __builtin_clz(n - 1));
		tree.resize(maxs);
		start = 0;
		end = n - 1;
		build(1, start, end, v);
	}
	Node query(int qs, int qe) {
		return query(1, start, end, qs, qe);
	}
	Node query(int p) {
		return query(1, start, end, p, p);
	}
	void query(int qs, int qe, const function<void(Node&, int, int)>& f) {
		if (qs > qe) return;
		query(1, start, end, qs, qe, f);
	}
	template <typename... T>
	void update(int qs, int qe, const T&... v) {
		update(1, start, end, qs, qe, v...);
	}
};
int main() {
	for (int i = 1; i <= 9; ++i)
		for (int j = 1; j < MAX; ++j) {
			sames[i][j] = sames[i][j - 1] * 10 + i;
		}
	p10[0] = 1;
	for (int j = 1; j < MAX; ++j) p10[j] = p10[j - 1] * 10;
	int n, q;
	scanf("%d%d", &n, &q);
	SegTree st(n);
	while (q--) {
		int l, r, d;
		scanf("%d%d%d", &l, &r, &d);
		--l;
		--r;
		st.update(l, r, d);
		printf("%d\n", st.query(0, n - 1).x.val);
	}
}


Measured memory_bytes: 22280