#include <bits/stdc++.h>
using namespace std;
inline int read() {
  int x = 0, f = 1;
  char ch = getchar();
  while (ch > '9' || ch < '0') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    x = x * 10 + ch - '0';
    ch = getchar();
  }
  return x * f;
}
const int N = 1e6 + 1005, SZ = 1000;
const int M = 5e5 + 5;
const int NM = 1e5 + 5;
int fa[N], val[N];
int sz[M], rt[M];
int n, m;
int a[N];
int pos[N];
int Max;
int tag;
int ANS[M];
int OPT[M], L[M], R[M], X[M];
struct BLOCK {
  int l, r;
  inline int getfa(int x) {
    if (fa[x] == x) return x;
    return fa[x] = getfa(fa[x]);
  }
  inline void merge(int x, int y) {
    if (rt[y])
      fa[rt[x]] = rt[y];
    else {
      rt[y] = rt[x];
      val[rt[y]] = y;
    }
    sz[y] += sz[x];
    rt[x] = sz[x] = 0;
  }
  inline void Break() {
    for (int i = l; i <= r; i++) {
      a[i] = val[getfa(i)];
      sz[a[i]] = rt[a[i]] = 0;
      a[i] -= tag;
    }
    for (int i = l; i <= r; i++) fa[i] = 0;
    tag = 0;
  }
  inline void Build() {
    Max = 0;
    for (int i = l; i <= r; i++) {
      Max = max(Max, a[i]);
      if (rt[a[i]] == 0) {
        fa[i] = i;
        rt[a[i]] = i;
        val[i] = a[i];
      } else
        fa[i] = rt[a[i]];
      sz[a[i]]++;
    }
  }
  inline void update(int _L, int _R, int x) {
    if (_L > _R) return;
    Break();
    for (int i = _L; i <= _R; i++)
      if (a[i] > x) a[i] -= x;
    Build();
  }
  inline void UPDATE(int x) {
    if (Max - tag >= x * 2) {
      for (int i = tag + 1; i <= tag + x; i++)
        if (rt[i]) merge(i, i + x);
      tag += x;
    } else {
      for (int i = Max; i > tag + x; i--)
        if (rt[i]) merge(i, i - x);
      Max = min(tag + x, Max);
    }
  }
  inline int query(int _L, int _R, int x) {
    int ans = 0;
    for (int i = _L; i <= _R; i++)
      if (val[getfa(i)] - tag == x) ans++;
    return ans;
  }
  inline int QUERY(int x) {
    if (x + tag > 5e5) return 0;
    return sz[x + tag];
  }
} B;
signed main() {
  n = read();
  m = read();
  for (int i = 1; i <= n; i++) a[i] = read();
  for (int i = 1; i <= n; i++) pos[i] = (i - 1) / SZ + 1;
  for (int i = 1; i <= m; i++) {
    OPT[i] = read();
    L[i] = read();
    R[i] = read();
    X[i] = read();
  }
  for (int k = 1; k <= pos[n]; k++) {
    B.l = (k - 1) * SZ + 1, B.r = min(k * SZ, n);
    B.Build();
    for (int i = 1; i <= m; i++) {
      if (OPT[i] == 1) {
        if (L[i] <= B.l && R[i] >= B.r)
          B.UPDATE(X[i]);
        else
          B.update(max(L[i], B.l), min(R[i], B.r), X[i]);
      } else {
        int ans = 0;
        if (L[i] <= B.l && R[i] >= B.r)
          ans = B.QUERY(X[i]);
        else
          ans = B.query(max(L[i], B.l), min(R[i], B.r), X[i]);
        ANS[i] += ans;
      }
    }
  }
  for (int i = 1; i <= m; i++)
    if (OPT[i] == 2) printf("%d\n", ANS[i]);
}
