#include <bits/stdc++.h>
using namespace std;
const int P = 998244353;
int add(int a, int b) {
  if ((a += b) >= P) a -= P;
  return a;
}
int sub(int a, int b) {
  if ((a -= b) < 0) a += P;
  return a;
}
int mul(int a, int b) { return 1ll * a * b % P; }
int kpow(int a, int b) {
  int r = 1;
  for (; b; b >>= 1, a = mul(a, a)) {
    if (b & 1) r = mul(r, a);
  }
  return r;
}
const int N = 200005;
set<pair<int, int> > S[N];
set<pair<int, int> >::iterator itl, itr, it;
int tree[N << 2], Add[N << 2], Mul[N << 2];
void up(int node) { tree[node] = add(tree[node << 1], tree[node << 1 | 1]); }
void down(int l, int r, int node) {
  if (Mul[node] != 1) {
    Mul[node << 1] = mul(Mul[node << 1], Mul[node]);
    Mul[node << 1 | 1] = mul(Mul[node << 1 | 1], Mul[node]);
    Add[node << 1] = mul(Add[node << 1], Mul[node]);
    Add[node << 1 | 1] = mul(Add[node << 1 | 1], Mul[node]);
    tree[node << 1] = mul(tree[node << 1], Mul[node]);
    tree[node << 1 | 1] = mul(tree[node << 1 | 1], Mul[node]);
    Mul[node] = 1;
  }
  if (Add[node]) {
    Add[node << 1] = add(Add[node << 1], Add[node]);
    Add[node << 1 | 1] = add(Add[node << 1 | 1], Add[node]);
    int mid = (l + r) >> 1;
    tree[node << 1] = add(tree[node << 1], mul(mid - l + 1, Add[node]));
    tree[node << 1 | 1] = add(tree[node << 1 | 1], mul(r - mid, Add[node]));
    Add[node] = 0;
  }
}
void upd(int l, int r, int node, int _l, int _r, int num) {
  if (_l == l && _r == r) {
    if (l != r) down(l, r, node);
    if (num == 0) {
      Add[node] = add(Add[node], 1);
      tree[node] = add(tree[node], r - l + 1);
    } else {
      Mul[node] = mul(Mul[node], 2);
      Add[node] = mul(Add[node], 2);
      tree[node] = mul(tree[node], 2);
    }
    return;
  } else if (l == r)
    return;
  int mid = (l + r) >> 1;
  down(l, r, node);
  if (_r <= mid)
    upd(l, mid, node << 1, _l, _r, num);
  else if (_l > mid)
    upd(mid + 1, r, node << 1 | 1, _l, _r, num);
  else {
    upd(l, mid, node << 1, _l, mid, num);
    upd(mid + 1, r, node << 1 | 1, mid + 1, _r, num);
  }
  up(node);
}
int query(int l, int r, int node, int _l, int _r) {
  if (l != r) down(l, r, node);
  int mid = (l + r) >> 1;
  if (_l > r || _r < l)
    return 0;
  else if (_l <= l && _r >= r)
    return tree[node];
  else
    return add(query(l, mid, node << 1, _l, _r),
               query(mid + 1, r, node << 1 | 1, _l, _r));
}
int main() {
  for (int i = (0); i < (N << 2); i++) Mul[i] = 1;
  int n, q;
  scanf("%d%d", &n, &q);
  while (q--) {
    int co;
    scanf("%d", &co);
    if (co == 1) {
      int l, r, x;
      scanf("%d%d%d", &l, &r, &x);
      itl = S[x].lower_bound(make_pair(l, -1));
      if (itl == S[x].end()) {
        upd(1, n, 1, l, r, 0);
        S[x].insert(make_pair(l, -1));
        S[x].insert(make_pair(r, 1));
        continue;
      }
      if (itl->second == 1) itl--;
      itr = S[x].upper_bound(make_pair(r, 1));
      if (itr == S[x].begin()) {
        upd(1, n, 1, l, r, 0);
        S[x].insert(make_pair(l, -1));
        S[x].insert(make_pair(r, 1));
        continue;
      }
      itr--;
      if (itr->second == -1) itr++;
      itr++;
      vector<pair<int, int> > V;
      for (it = itl; it != itr;) {
        pair<int, int> a;
        a.first = it->first;
        S[x].erase(it++);
        if (it == itr) assert(0);
        a.second = it->first;
        S[x].erase(it++);
        V.push_back(a);
      }
      int minl = l, maxr = r;
      int now = l;
      for (int i = (0); i < ((int)V.size()); i++) {
        minl = min(minl, V[i].first);
        maxr = max(maxr, V[i].second);
        if (V[i].first > now)
          upd(1, n, 1, now, V[i].first - 1, 0), now = V[i].first;
        if (r <= V[i].second)
          upd(1, n, 1, now, r, 1), now = r + 1;
        else
          upd(1, n, 1, now, V[i].second, 1), now = V[i].second + 1;
      }
      if (now <= r) upd(1, n, 1, now, r, 0);
      S[x].insert(make_pair(minl, -1));
      S[x].insert(make_pair(maxr, 1));
    } else {
      int l, r;
      scanf("%d%d", &l, &r);
      printf("%d\n", query(1, n, 1, l, r));
    }
  }
  return 0;
}
