#include <bits/stdc++.h>
using namespace std;
namespace IO {
char BB[1 << 23], *SS = BB, *TT = BB;
template <typename T>
inline void read(T &x) {
  x = 0;
  int fu = 1;
  char c =
      (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
           ? EOF
           : *SS++);
  while (c > 57 || c < 48) {
    if (c == 45) fu = -1;
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  }
  while (c <= 57 && c >= 48) {
    x = x * 10 + c - 48;
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  }
  x *= fu;
}
template <typename T>
inline void readp(T &x) {
  x = 0;
  int fu = 1;
  char c =
      (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
           ? EOF
           : *SS++);
  while (c > 57 || c < 48) {
    if (c == 45) fu = -1;
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  }
  while (c <= 57 && c >= 48) {
    x = x * 10 + c - 48;
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  }
  if (c == 46) {
    double y = 1;
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
    while (c <= 57 && c >= 48) {
      x = x + (y *= 0.1) * (c - 48);
      c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
               ? EOF
               : *SS++);
    }
  }
  x *= fu;
}
inline void readc(char &x) {
  char c =
      (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
           ? EOF
           : *SS++);
  while (c == ' ' || c == '\n' || c == '\r')
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  x = c;
}
inline void reads(char x[], int pos = 0) {
  char c =
      (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
           ? EOF
           : *SS++);
  while (c == ' ' || c == '\n' || c == '\r')
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  while (c ^ ' ' && c ^ '\n' && c ^ '\r')
    x[pos++] = c,
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  x[pos] = '\0';
}
inline void readl(char x[], int pos = 0) {
  char c =
      (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
           ? EOF
           : *SS++);
  while (c == '\n' || c == '\r')
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  while (c ^ '\n' && c ^ '\r')
    x[pos++] = c,
    c = (SS == TT && (TT = (SS = BB) + fread(BB, 1, 1 << 23, stdin), SS == TT)
             ? EOF
             : *SS++);
  x[pos] = '\0';
}
char out[1 << 22], *Out = out;
inline void putcha(char x) {
  *Out++ = x;
  if (Out - out >= (1 << 22)) fwrite(out, 1, Out - out, stdout), Out = out;
}
template <typename T>
inline void fprint(T x) {
  if (x < 0) putcha(45), x = -x;
  if (x > 9) fprint(x / 10);
  putcha(x % 10 + 48);
}
template <typename T>
inline void fprint(T x, char ch) {
  fprint(x);
  putcha(ch);
}
inline void prints(char c[]) {
  int pos = 0;
  while (c[pos] != '\0') putcha(c[pos++]);
}
inline void prints(char c[], char ch) {
  int pos = 0;
  while (c[pos] != '\0') putcha(c[pos++]);
  putcha(ch);
}
inline void prints(const char c[]) {
  int pos = 0;
  while (c[pos] != '\0') putcha(c[pos++]);
}
inline void prints(const char c[], char ch) {
  int pos = 0;
  while (c[pos] != '\0') putcha(c[pos++]);
  putcha(ch);
}
}  // namespace IO
using namespace IO;
void write(int x) {
  if (x < 0) {
    putchar('-');
    x = (-x);
  }
  if (x > 9) write(x / 10);
  putchar((x % 10) + '0');
}
void writeln(int x) {
  write(x);
  puts("");
}
const int N = 1e6 + 95;
const int M = 1e6 + 95;
const int SqrtN = 1e4 + 95;
int n, m, a[N], Block, len, pos[N];
int ql[SqrtN], qr[SqrtN];
struct query {
  int opt, l, r, x;
} q[M];
int ans[M];
int fa[N], rt[N], cnt[N];
int val[N], tmp, tag;
int find(int x) {
  if (fa[x] == x) return x;
  return (fa[x] = find(fa[x]));
}
void Merge(int x, int y) {
  if (!rt[x]) return;
  if (!rt[y]) {
    rt[y] = rt[x];
    val[rt[x]] = y;
  } else {
    fa[rt[x]] = rt[y];
  }
  cnt[y] += cnt[x];
  rt[x] = 0;
  cnt[x] = 0;
}
void Build(int l, int r) {
  tmp = 0;
  tag = 0;
  for (int i = l; i <= r; i++) {
    tmp = max(tmp, a[i]);
    cnt[a[i]]++;
    if (rt[a[i]]) {
      fa[i] = rt[a[i]];
    } else {
      val[i] = a[i];
      rt[a[i]] = i;
      fa[i] = i;
    }
  }
  return;
}
void Updata(int p, int x) {
  if ((tmp - tag) > (x * 2)) {
    for (int i = tag + 1; i <= tag + x; i++) Merge(i, i + x);
    tag += x;
  } else {
    for (int i = x + tag + 1; i <= tmp; i++) Merge(i, i - x);
    tmp = min(tmp, x + tag);
  }
  return;
}
void Rebuild(int l, int r, int p, int x) {
  for (int i = l; i <= r; i++) {
    a[i] = val[find(i)];
    if (rt[a[i]]) {
      rt[a[i]] = 0;
      cnt[a[i]] = 0;
    }
  }
  for (int i = l; i <= r; i++) {
    a[i] -= tag;
    val[i] = 0;
  }
  for (int i = max(l, q[p].l); i <= min(r, q[p].r); i++)
    if (q[p].x < a[i]) a[i] -= q[p].x;
  Build(l, r);
  return;
}
int Query(int l, int r, int p, int x) {
  if ((x + tag) > (1e5 + 1)) return 0;
  if (q[p].l <= l && r <= q[p].r) {
    return cnt[(x + tag)];
  }
  int step = 0;
  for (int i = max(l, q[p].l); i <= min(r, q[p].r); i++) {
    if ((val[find(i)] - tag) == x) step++;
  }
  return step;
}
int main() {
  read(n);
  read(m);
  len = sqrt(n);
  Block = (n + len - 1) / len;
  for (int i = 1; i <= n; i++) pos[i] = ((i - 1) / len + 1);
  for (int i = 1; i <= Block; i++) ql[i] = max(1, (i - 1) * len + 1);
  for (int i = 1; i <= Block; i++) qr[i] = min(n, i * len);
  for (int i = 1; i <= n; i++) read(a[i]);
  for (int i = 1; i <= m; i++) {
    read(q[i].opt);
    read(q[i].l);
    read(q[i].r);
    read(q[i].x);
  }
  for (int i = 1; i <= Block; i++) {
    memset(rt, 0, sizeof(rt));
    memset(cnt, 0, sizeof(cnt));
    Build(ql[i], qr[i]);
    for (int j = 1; j <= m; j++) {
      if (q[j].r < ql[i] || qr[i] < q[j].l) continue;
      if (q[j].opt == 1) {
        if (q[j].l <= ql[i] && qr[i] <= q[j].r)
          Updata(j, q[j].x);
        else
          Rebuild(ql[i], qr[i], j, q[j].x);
      } else {
        ans[j] += Query(ql[i], qr[i], j, q[j].x);
      }
    }
  }
  for (int i = 1; i <= m; i++)
    if (q[i].opt == 2) writeln(ans[i]);
  return 0;
}
