#include <bits/stdc++.h>
using namespace std;
char bu[1000005], *cr, *cl;
void rd(int &x) {
  x = 0;
  int f = 1;
  char ch =
      cl == cr && (cr = (cl = bu) + fread(bu, 1, 1000000, stdin), cl == cr)
          ? EOF
          : *cl++;
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = cl == cr && (cr = (cl = bu) + fread(bu, 1, 1000000, stdin), cl == cr)
             ? EOF
             : *cl++;
  }
  while (isdigit(ch))
    x = x * 10 + ch - '0',
    ch = cl == cr && (cr = (cl = bu) + fread(bu, 1, 1000000, stdin), cl == cr)
             ? EOF
             : *cl++;
  x *= f;
}
const int N = 1e6 + 5, M = 5e5 + 5, V = 5e5 + 5;
int n, m, mx, tag;
int a[N], ans[M], s[N], rt[V], cnt[V], c[N];
struct query {
  int o, l, r, x;
} b[M];
bool flag = 0;
int getset(int x) { return s[x] == x ? x : s[x] = getset(s[x]); }
void merge(int u, int v) {
  if (u > mx || v > mx || !rt[v]) return;
  if (rt[u])
    s[rt[v]] = rt[u];
  else {
    rt[u] = rt[v];
    c[rt[u]] = u;
  }
  cnt[u] += cnt[v], rt[v] = cnt[v] = 0;
}
void rebuild(int ql, int qr, int l, int r, int x) {
  for (int i = ql; i <= qr; ++i)
    a[i] = c[getset(i)], cnt[a[i]] = rt[a[i]] = 0, a[i] -= tag;
  int nl = max(ql, l), nr = min(qr, r);
  for (int i = ql; i <= qr; ++i) c[i] = 0;
  for (int i = nl; i <= nr; ++i)
    if (a[i] > x) a[i] -= x;
  tag = 0, mx = 0;
  for (int i = ql; i <= qr; ++i) {
    mx = max(mx, a[i]);
    if (!rt[a[i]])
      rt[a[i]] = s[i] = i, c[i] = a[i];
    else
      s[i] = rt[a[i]];
    cnt[a[i]]++;
  }
}
void work(int ql, int qr) {
  mx = 0, tag = 0;
  memset(cnt, 0, sizeof(cnt));
  memset(rt, 0, sizeof(rt));
  for (int i = ql; i <= qr; ++i) {
    mx = max(mx, a[i]);
    if (!rt[a[i]])
      rt[a[i]] = s[i] = i, c[i] = a[i];
    else
      s[i] = rt[a[i]];
    cnt[a[i]]++;
  }
  for (int i = 1; i <= m; ++i) {
    if (b[i].r < ql || b[i].l > qr || b[i].x > mx) continue;
    if (b[i].o == 1) {
      if (b[i].l <= ql && qr <= b[i].r) {
        if (b[i].x * 2 >= mx - tag) {
          for (int j = mx; j >= b[i].x + 1 + tag; --j) merge(j - b[i].x, j);
          if (tag + b[i].x < mx) mx = tag + b[i].x;
        } else {
          for (int j = tag + 1; j <= tag + b[i].x; ++j) merge(j + b[i].x, j);
          tag += b[i].x;
        }
      } else
        rebuild(ql, qr, b[i].l, b[i].r, b[i].x);
    } else {
      if (b[i].x + tag > mx) continue;
      if (b[i].l <= ql && qr <= b[i].r) {
        ans[i] += cnt[b[i].x + tag];
      } else {
        int nl = max(ql, b[i].l), nr = min(qr, b[i].r), nx = b[i].x + tag;
        for (int j = nl; j <= nr; ++j)
          if (c[getset(j)] == nx) ans[i]++;
      }
    }
  }
}
int main() {
  rd(n), rd(m);
  for (int i = 1; i <= n; ++i) rd(a[i]);
  for (int i = 1; i <= m; ++i) rd(b[i].o), rd(b[i].l), rd(b[i].r), rd(b[i].x);
  int block = 1000;
  for (int i = 1; i <= (n + block - 1) / block; ++i)
    work(block * (i - 1) + 1, min(i * block, n));
  for (int i = 1; i <= m; ++i)
    if (b[i].o == 2) cout << ans[i] << '\n';
  return 0;
}
