#include <bits/stdc++.h>
using namespace std;
template <typename T>
bool chkmax(T &a, T b) {
  return a < b ? a = b, 1 : 0;
}
template <typename T>
bool chkmin(T &a, T b) {
  return a > b ? a = b, 1 : 0;
}
const int maxn = 200000 + 100;
const int modd = 998244353;
const int inv2 = 499122177;
struct node {
  int l, r;
  bool operator<(const node &aa) const {
    return ((l < aa.l) || (l == aa.l && r < aa.r));
  }
};
int n, m;
set<node> s[maxn];
int sum[maxn << 2], add[maxn << 2], mul[maxn << 2];
inline void file() {
  freopen("multiset.in", "r", stdin);
  freopen("multiset.out", "w", stdout);
}
inline int read() {
  int x = 0, p = 1;
  char c = getchar();
  while (!isdigit(c)) {
    if (c == '-') p = -1;
    c = getchar();
  }
  while (isdigit(c)) {
    x = (x << 1) + (x << 3) + (c - '0');
    c = getchar();
  }
  return x * p;
}
void split(int x, int pos) {
  set<node>::iterator it = s[x].lower_bound((node){pos, pos});
  if (it == s[x].begin()) return;
  --it;
  if (it->l < pos && pos <= it->r) {
    s[x].insert((node){it->l, pos - 1});
    s[x].insert((node){pos, it->r});
    s[x].erase(it);
  }
}
inline void Add(int &a, int b) {
  a += b;
  if (a >= modd) a -= modd;
  if (a < 0) a += modd;
}
inline void pushdown(int h, int l, int mid, int r) {
  sum[(h << 1)] = 1ll * sum[(h << 1)] * mul[h] % modd;
  sum[(h << 1) | 1] = 1ll * sum[(h << 1) | 1] * mul[h] % modd;
  add[(h << 1)] = 1ll * add[(h << 1)] * mul[h] % modd;
  add[(h << 1) | 1] = 1ll * add[(h << 1) | 1] * mul[h] % modd;
  mul[(h << 1)] = 1ll * mul[(h << 1)] * mul[h] % modd;
  mul[(h << 1) | 1] = 1ll * mul[(h << 1) | 1] * mul[h] % modd;
  Add(sum[(h << 1)], 1ll * (mid - l + 1) * add[h] % modd);
  Add(sum[(h << 1) | 1], 1ll * (r - mid) * add[h] % modd);
  Add(add[(h << 1)], add[h]);
  Add(add[(h << 1) | 1], add[h]);
  add[h] = 0;
  mul[h] = 1;
}
void update(int h, int l, int r, int L, int R, int Plus, int Mul) {
  if (L <= l && r <= R) {
    if (Mul) {
      sum[h] = 1ll * sum[h] * Mul % modd;
      add[h] = 1ll * add[h] * Mul % modd;
      mul[h] = 1ll * mul[h] * Mul % modd;
    }
    if (Plus) {
      Add(sum[h], 1ll * (r - l + 1) * Plus % modd);
      Add(add[h], Plus);
    }
    return;
  }
  int mid = (l + r) / 2;
  if (add[h] || mul[h] != 1) pushdown(h, l, mid, r);
  if (L <= mid) update((h << 1), l, mid, L, R, Plus, Mul);
  if (mid < R) update((h << 1) | 1, mid + 1, r, L, R, Plus, Mul);
  sum[h] = (sum[(h << 1)] + sum[(h << 1) | 1]) % modd;
}
int query(int h, int l, int r, int L, int R) {
  if (L <= l && r <= R) return sum[h];
  int mid = (l + r) / 2, ans = 0;
  if (add[h] || mul[h] != 1) pushdown(h, l, mid, r);
  if (L <= mid) Add(ans, query((h << 1), l, mid, L, R));
  if (mid < R) Add(ans, query((h << 1) | 1, mid + 1, r, L, R));
  return ans;
}
int main() {
  n = read();
  m = read();
  for (int i = (int)0; i <= (int)(n << 2); ++i) add[i] = 0, mul[i] = 1;
  for (int i = (int)1; i <= (int)n; ++i) s[i].insert((node){1, n});
  while (m--) {
    int w = read(), l = read(), r = read();
    if (w == 1) {
      int x = read();
      split(x, l);
      split(x, r + 1);
      update(1, 1, n, l, r, 0, 2);
      while (1) {
        set<node>::iterator it = s[x].lower_bound((node){l, l});
        if (it == s[x].end() || it->l > r) break;
        update(1, 1, n, it->l, it->r, 1, inv2);
        s[x].erase(it);
      }
    } else {
      printf("%d\n", query(1, 1, n, l, r));
    }
  }
  return 0;
}
