#include <bits/stdc++.h>
const int MAXN = 200000 + 10, Mod = 998244353;
int n, q, qm, an, qn;
struct node {
  int l, r, x, tm;
  inline bool operator<(const node &A) const { return x < A.x; };
};
node act[MAXN];
struct ques {
  int l, r, tm;
};
ques qs[MAXN];
struct DFT {
  int l, r, opt, tm;
};
std::vector<DFT> V;
template <typename T>
inline void read(T &x) {
  T data = 0, w = 1;
  char ch = 0;
  while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
  if (ch == '-') w = -1, ch = getchar();
  while (ch >= '0' && ch <= '9')
    data = ((T)data << 3) + ((T)data << 1) + (ch ^ '0'), ch = getchar();
  x = data * w;
}
template <typename T>
inline void write(T x, char ch = '\0') {
  if (x < 0) putchar('-'), x = -x;
  if (x > 9) write(x / 10);
  putchar(x % 10 + '0');
  if (ch != '\0') putchar(ch);
}
template <typename T>
inline void chkmin(T &x, T y) {
  x = (y < x ? y : x);
}
template <typename T>
inline void chkmax(T &x, T y) {
  x = (y > x ? y : x);
}
template <typename T>
inline T min(T x, T y) {
  return x < y ? x : y;
}
template <typename T>
inline T max(T x, T y) {
  return x > y ? x : y;
}
inline bool cmp(DFT a, DFT b) { return a.tm < b.tm; }
struct Segment_Tree_1 {
  int sum[MAXN << 2], let[MAXN << 2];
  inline void init() { memset(let, -1, sizeof(let)); }
  inline void Clear() { sum[1] = let[1] = 0; }
  inline void PushUp(int rt) { sum[rt] = sum[rt << 1] + sum[rt << 1 | 1]; }
  inline void PushDown(int rt, int len) {
    sum[rt << 1] = let[rt] * (len - (len >> 1));
    sum[rt << 1 | 1] = let[rt] * (len >> 1);
    let[rt << 1] = let[rt << 1 | 1] = let[rt];
    let[rt] = -1;
  }
  inline void Update(int rt, int l, int r, int L, int R, int tm) {
    if (L <= l && r <= R && (sum[rt] == r - l + 1 || sum[rt] == 0)) {
      if (sum[rt] == r - l + 1)
        V.push_back((DFT){l, r, 2, tm});
      else
        sum[rt] = r - l + 1, let[rt] = 1, V.push_back((DFT){l, r, 1, tm});
    } else {
      if (let[rt] != -1) PushDown(rt, r - l + 1);
      if (L <= ((l + r) >> 1)) Update(rt << 1, l, ((l + r) >> 1), L, R, tm);
      if (R > ((l + r) >> 1))
        Update(rt << 1 | 1, ((l + r) >> 1) + 1, r, L, R, tm);
      PushUp(rt);
    }
  }
};
Segment_Tree_1 T1;
struct Segment_Tree_2 {
  int sum[MAXN << 2], add[MAXN << 2], mul[MAXN << 2];
  inline void init() { memset(mul, 1, sizeof(mul)); }
  inline void PushUp(int rt) {
    sum[rt] = (sum[rt << 1] + sum[rt << 1 | 1]) % Mod;
  }
  inline void PushDown(int rt, int len) {
    if (mul[rt] > 1) {
      sum[rt << 1] = 1ll * sum[rt << 1] * mul[rt] % Mod;
      sum[rt << 1 | 1] = 1ll * sum[rt << 1 | 1] * mul[rt] % Mod;
      add[rt << 1] = 1ll * add[rt << 1] * mul[rt] % Mod;
      add[rt << 1 | 1] = 1ll * add[rt << 1 | 1] * mul[rt] % Mod;
      mul[rt << 1] = 1ll * mul[rt << 1] * mul[rt] % Mod;
      mul[rt << 1 | 1] = 1ll * mul[rt << 1 | 1] * mul[rt] % Mod;
      mul[rt] = 1;
    }
    if (add[rt]) {
      sum[rt << 1] =
          (sum[rt << 1] + 1ll * add[rt] * (len - (len >> 1)) % Mod) % Mod;
      sum[rt << 1 | 1] =
          (sum[rt << 1 | 1] + 1ll * add[rt] * (len >> 1) % Mod) % Mod;
      add[rt << 1] = (add[rt << 1] + add[rt]) % Mod;
      add[rt << 1 | 1] = (add[rt << 1 | 1] + add[rt]) % Mod;
      add[rt] = 0;
    }
  }
  inline void Add_Update(int rt, int l, int r, int L, int R, int k) {
    if (L <= l && r <= R) {
      sum[rt] = (sum[rt] + 1ll * (r - l + 1) * k % Mod) % Mod;
      add[rt] = (add[rt] + k) % Mod;
    } else {
      PushDown(rt, r - l + 1);
      if (L <= ((l + r) >> 1)) Add_Update(rt << 1, l, ((l + r) >> 1), L, R, k);
      if (R > ((l + r) >> 1))
        Add_Update(rt << 1 | 1, ((l + r) >> 1) + 1, r, L, R, k);
      PushUp(rt);
    }
  }
  inline void Mul_Update(int rt, int l, int r, int L, int R, int k) {
    if (L <= l && r <= R) {
      sum[rt] = 1ll * sum[rt] * k % Mod;
      add[rt] = 1ll * add[rt] * k % Mod;
      mul[rt] = 1ll * mul[rt] * k % Mod;
    } else {
      PushDown(rt, r - l + 1);
      if (L <= ((l + r) >> 1)) Mul_Update(rt << 1, l, ((l + r) >> 1), L, R, k);
      if (R > ((l + r) >> 1))
        Mul_Update(rt << 1 | 1, ((l + r) >> 1) + 1, r, L, R, k);
      PushUp(rt);
    }
  }
  inline int Query(int rt, int l, int r, int L, int R) {
    if (L <= l && r <= R)
      return sum[rt];
    else {
      PushDown(rt, r - l + 1);
      int res = 0;
      if (L <= ((l + r) >> 1))
        res = (res + Query(rt << 1, l, ((l + r) >> 1), L, R)) % Mod;
      if (R > ((l + r) >> 1))
        res = (res + Query(rt << 1 | 1, ((l + r) >> 1) + 1, r, L, R)) % Mod;
      return res;
    }
  }
};
Segment_Tree_2 T2;
int main() {
  read(n);
  read(q);
  for (register int i = 1, opt, l, r, x; i <= q; ++i) {
    read(opt);
    if (opt == 1) {
      read(l);
      read(r);
      read(x);
      act[++an] = (node){l, r, x, i};
    }
    if (opt == 2) {
      read(l);
      read(r);
      qs[++qn] = (ques){l, r, i};
    }
  }
  std::stable_sort(act + 1, act + an + 1);
  T1.init();
  for (register int i = 1; i <= an; ++i) {
    if (i != 1 && act[i].x != act[i - 1].x) T1.Clear();
    T1.Update(1, 1, n, act[i].l, act[i].r, act[i].tm);
  }
  std::sort(V.begin(), V.end(), cmp);
  T2.init();
  int j = 1;
  for (register int i = 0, lt = V.size(); i < lt; ++i) {
    while (V[i].tm > qs[j].tm)
      write(T2.Query(1, 1, n, qs[j].l, qs[j].r), '\n'), ++j;
    if (V[i].opt == 1) T2.Add_Update(1, 1, n, V[i].l, V[i].r, 1);
    if (V[i].opt == 2) T2.Mul_Update(1, 1, n, V[i].l, V[i].r, 2);
  }
  while (j <= qn) write(T2.Query(1, 1, n, qs[j].l, qs[j].r), '\n'), ++j;
  return 0;
}
