#include <bits/stdc++.h>
using namespace std;
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c,
                                       qu[55];
int f, qr;
inline void flush() {
  fwrite(obuf, 1, oS - obuf, stdout);
  oS = obuf;
}
inline void pc(char x) {
  *oS++ = x;
  if (oS == oT) flush();
}
inline void gtc(char &x) {
  x = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                   (iS == iT ? EOF : *iS++))
                : *iS++);
}
template <class I>
inline void gi(I &x) {
  for (f = 1, c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                              (iS == iT ? EOF : *iS++))
                            : *iS++);
       c < '0' || c > '9';
       c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                       (iS == iT ? EOF : *iS++))
                     : *iS++))
    if (c == '-') f = -1;
  for (x = 0; c <= '9' && c >= '0';
       c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                       (iS == iT ? EOF : *iS++))
                     : *iS++))
    x = x * 10 + (c & 15);
  x *= f;
}
template <class I>
inline void print(I x) {
  if (!x) pc('0');
  if (x < 0) pc('-'), x = -x;
  while (x) qu[++qr] = x % 10 + '0', x /= 10;
  while (qr) pc(qu[qr--]);
}
struct Flusher_ {
  ~Flusher_() { flush(); }
} io_flusher_;
}  // namespace io
using io ::gi;
using io ::gtc;
using io ::pc;
using io ::print;
template <typename T>
inline void chkmax(T &a, T b) {
  a = a > b ? a : b;
}
template <typename T>
inline void chkmin(T &a, T b) {
  a = a < b ? a : b;
}
template <typename T>
inline T gcd(T &a, T b) {
  return !b ? a : gcd(b, a % b);
}
const int mod = 998244353;
template <typename T>
const T Mod(T x) {
  return x >= mod * 2 ? x % mod : (x >= mod ? x - mod : x);
}
template <typename T>
const void Add(T &a, T b) {
  a = Mod(a + b);
}
const int MAXN = 200100;
struct Node {
  int l, r;
  Node() {}
  Node(int l, int r) : l(l), r(r) {}
  inline bool in(int x) { return l <= x && x <= r; }
  friend bool operator<(Node a, Node b) { return a.r < b.r; }
} L, R;
set<Node> s[MAXN + 1];
struct Segment_Tree {
  struct Node {
    int v, t1, t2;
    Node() : t1(1) {}
  } T[MAXN << 2];
  inline void pushdown(int nd, int l, int r) {
    int &t1 = T[nd].t1, &t2 = T[nd].t2, mid = (l + r) >> 1;
    if (t1 == 1 && !t2) return;
    int Ll = mid - l + 1, Lr = r - mid;
    T[(nd << 1)].v = (1LL * T[(nd << 1)].v * t1 + 1LL * t2 * Ll) % mod;
    T[(nd << 1)].t2 = (1LL * T[(nd << 1)].t2 * t1 + t2) % mod;
    T[(nd << 1)].t1 = 1LL * T[(nd << 1)].t1 * t1 % mod;
    T[(nd << 1 | 1)].v = (1LL * T[(nd << 1 | 1)].v * t1 + 1LL * t2 * Lr) % mod;
    T[(nd << 1 | 1)].t2 = (1LL * T[(nd << 1 | 1)].t2 * t1 + t2) % mod;
    T[(nd << 1 | 1)].t1 = 1LL * T[(nd << 1 | 1)].t1 * t1 % mod;
    t1 = 1, t2 = 0;
  }
  inline void Prd(Node &x) {
    x.v = Mod(x.v << 1), x.t1 = Mod(x.t1 << 1), x.t2 = Mod(x.t2 << 1);
  }
  inline void Add(Node &x, int v) { x.v = Mod(x.v + v), x.t2 = Mod(x.t2 + 1); }
  inline void Mul(int nd, int l, int r, int L, int R) {
    if (L <= l && r <= R) return Prd(T[nd]);
    int mid = (l + r) >> 1;
    pushdown(nd, l, r);
    if (L <= mid) Mul((nd << 1), l, mid, L, R);
    if (mid < R) Mul((nd << 1 | 1), mid + 1, r, L, R);
    T[nd].v = Mod(T[(nd << 1)].v + T[(nd << 1 | 1)].v);
  }
  inline void Pls(int nd, int l, int r, int L, int R) {
    if (L <= l && r <= R) return Add(T[nd], r - l + 1);
    int mid = (l + r) >> 1;
    pushdown(nd, l, r);
    if (L <= mid) Pls((nd << 1), l, mid, L, R);
    if (mid < R) Pls((nd << 1 | 1), mid + 1, r, L, R);
    T[nd].v = Mod(T[(nd << 1)].v + T[(nd << 1 | 1)].v);
  }
  inline int Query(int nd, int l, int r, int L, int R) {
    if (L <= l && r <= R) return T[nd].v;
    int mid = (l + r) >> 1;
    pushdown(nd, l, r);
    if (mid < L) return Query((nd << 1 | 1), mid + 1, r, L, R);
    if (R <= mid) return Query((nd << 1), l, mid, L, R);
    return Mod(Query((nd << 1 | 1), mid + 1, r, L, R) +
               Query((nd << 1), l, mid, L, R));
  }
} seg;
int main() {
  int n, q;
  gi(n), gi(q);
  for (int i = 1; i <= n; i++)
    s[i].insert(Node(0, 0)), s[i].insert(Node(n + 1, n + 1));
  while (q--) {
    int opt, l, r, x;
    gi(opt), gi(l), gi(r);
    if (opt == 1) {
      gi(x);
      int lft = l, segl = l, segr = r;
      L = *s[x].lower_bound(Node(l, l));
      while (L.l <= r) {
        s[x].erase(L);
        if (L.l > lft) seg.Pls(1, 1, n, lft, L.l - 1);
        int Ml = max(lft, L.l), Mr = min(r, L.r);
        if (Ml <= Mr) seg.Mul(1, 1, n, Ml, Mr);
        lft = L.r + 1, segl = min(segl, L.l), segr = max(segr, L.r);
        L = *s[x].lower_bound(Node(l, l));
      }
      if (lft <= r) seg.Pls(1, 1, n, lft, r);
      s[x].insert(Node(segl, segr));
    } else
      print(seg.Query(1, 1, n, l, r)), pc('\n');
  }
  return 0;
}
