#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
const int MAXN = 200010;
int get() {
  int x;
  bool f = 0;
  char c;
  while (!isdigit(c = getchar()))
    if (c == '-') f = 1;
  x = c - 48;
  while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + c - 48;
  if (f)
    return -x;
  else
    return x;
}
int add(int x, int v) {
  x += v;
  if (x >= MOD) x -= MOD;
  return x;
}
int N, M;
class SegT {
 private:
  struct node {
    int sum, len, k, b;
    node *ch[2];
    void mul(int a) {
      sum = 1LL * sum * a % MOD;
      k = 1LL * k * a % MOD;
      b = 1LL * b * a % MOD;
    }
    void Add(int v) {
      sum = add(sum, 1LL * v * len % MOD);
      b = add(b, v);
    }
    void down() {
      if (k != 1) {
        ch[0]->mul(k);
        ch[1]->mul(k);
        k = 1;
      }
      if (b) {
        ch[0]->Add(b);
        ch[1]->Add(b);
        b = 0;
      }
    }
    void up() { sum = add(ch[0]->sum, ch[1]->sum); }
  } * root, *null, *cnt, tree[MAXN << 1];
  void newnode(node *x, int len) {
    x->k = 1;
    x->b = 0;
    x->sum = 0;
    x->len = len;
    x->ch[0] = x->ch[1] = null;
  }
  void build(node *&x, int l, int r) {
    x = ++cnt, newnode(x, r - l + 1);
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(x->ch[0], l, mid);
    build(x->ch[1], mid + 1, r);
  }
  void update(node *x, int L, int R, int f, int l, int r) {
    if (L <= l && R >= r) {
      if (!f)
        x->mul(2);
      else
        x->Add(1);
      return;
    }
    x->down();
    int mid = (l + r) >> 1;
    if (L <= mid) update(x->ch[0], L, R, f, l, mid);
    if (R > mid) update(x->ch[1], L, R, f, mid + 1, r);
    x->up();
  }
  int ask(node *x, int L, int R, int l, int r) {
    if (L <= l && R >= r) return x->sum;
    x->down();
    int mid = (l + r) >> 1;
    int sum = 0;
    if (L <= mid) sum = ask(x->ch[0], L, R, l, mid);
    if (R > mid) sum = add(sum, ask(x->ch[1], L, R, mid + 1, r));
    return sum;
  }

 public:
  void newSegT() {
    cnt = tree;
    null = ++cnt, newnode(null, 0);
    build(root, 1, N);
  }
  void Update(int L, int R, int f) {
    if (L > R) return;
    update(root, L, R, f, 1, N);
  }
  int Ask(int L, int R) { return ask(root, L, R, 1, N); }
} T;
struct Seg {
  int l, r;
  void init(int _l, int _r) {
    l = _l;
    r = _r;
  }
  bool operator<(const Seg &a) const { return l < a.l || l == a.l && r < a.r; }
};
set<Seg> s[MAXN];
set<Seg>::iterator it, it2, It[MAXN];
int main() {
  N = get();
  M = get();
  T.newSegT();
  int type, a, b, v, l, r, p;
  Seg t;
  for (int i = 1; i <= M; ++i) {
    type = get();
    a = get();
    b = get();
    if (type == 1) {
      l = p = a, r = b;
      v = get();
      t.init(a, b);
      if (s[v].empty()) {
        T.Update(a, b, 1);
        s[v].insert(t);
        continue;
      }
      int cnt = 0;
      it = s[v].lower_bound(t);
      it2 = it;
      if (it2 != s[v].begin()) {
        --it2;
        if (it2->r >= a) {
          if (it2->r <= b) {
            l = it2->l;
            T.Update(a, it2->r, 0);
            p = it2->r + 1;
            It[++cnt] = it2;
          } else {
            T.Update(a, b, 0);
            continue;
          }
        }
      }
      while (it != s[v].end()) {
        if (it->r > b) break;
        T.Update(p, it->l - 1, 1);
        T.Update(it->l, it->r, 0);
        p = it->r + 1;
        It[++cnt] = it;
        ++it;
      }
      if (it != s[v].end() && it->l <= b) {
        T.Update(p, it->l - 1, 1);
        T.Update(it->l, b, 0);
        r = it->r;
        It[++cnt] = it;
        ++it;
      } else
        T.Update(p, b, 1);
      for (int j = 1; j <= cnt; ++j) s[v].erase(It[j]);
      t.init(l, r);
      s[v].insert(t);
    } else
      printf("%d\n", T.Ask(a, b));
  }
  return 0;
}
