#include <bits/stdc++.h>
using namespace std;
inline int read() {
  int x = 0, f = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    x = x * 10 + ch - '0';
    ch = getchar();
  }
  return x * f;
}
int sz[100005], fa[100005];
namespace UnionSet {
int FindFa(int i) { return fa[i] == i ? i : fa[i] = FindFa(fa[i]); }
void Merge(int x, int y, int *key, int *val, int *sz) {
  if (key[y]) {
    fa[key[x]] = key[y];
  } else {
    key[y] = key[x];
    val[key[x]] = y;
  }
  sz[y] += sz[x];
  key[x] = sz[x] = 0;
}
}  // namespace UnionSet
using namespace UnionSet;
int Size;
int a[100005], pos[100005];
struct Block {
  int sz[100005];
  int key[100005];
  int val[100005];
  int l, r, tag, maxn;
  int GetHead(int i) { return val[FindFa(i)]; }
  void Build() {
    maxn = 0;
    for (int i = l; i <= r; ++i) {
      maxn = max(maxn, a[i]);
      if (key[a[i]])
        fa[i] = key[a[i]];
      else
        val[i] = a[i], fa[i] = i, key[a[i]] = i;
      sz[a[i]]++;
    }
  }
  void pushdown() {
    for (int i = l; i <= r; ++i) {
      a[i] = GetHead(i);
      key[a[i]] = sz[a[i]] = 0;
      a[i] -= tag;
    }
    for (int i = l; i <= r; ++i) fa[i] = 0;
    tag = 0;
  }
  int GetSize(int v) {
    if (v > 100000) return 0;
    return sz[v];
  }
  void Delete(int v) {
    if (v * 2 <= maxn - tag) {
      for (int i = tag + 1; i <= tag + v; ++i) {
        if (key[i]) {
          Merge(i, i + v, key, val, sz);
        }
      }
      tag += v;
    } else {
      for (int i = maxn; i > tag + v; --i) {
        if (key[i]) {
          Merge(i, i - v, key, val, sz);
        }
      }
      maxn = min(maxn, tag + v);
    }
  }
} B[355];
int n, m;
void BruteForceDelete(int l, int r, int v) {
  for (int i = l; i <= r; ++i)
    if (a[i] > v) a[i] -= v;
}
void Update(int l, int r, int v) {
  int lid = pos[l], rid = pos[r];
  if (lid == rid) {
    B[lid].pushdown();
    BruteForceDelete(l, r, v);
    return;
  }
  B[lid].pushdown(), B[rid].pushdown();
  BruteForceDelete(l, B[lid].r, v);
  BruteForceDelete(B[rid].l, r, v);
  B[lid].Build(), B[rid].Build();
  for (int i = lid + 1; i <= rid - 1; ++i) B[i].Delete(v);
}
int BruteForceQuery(int l, int r, int v) {
  printf("%d %d %d\n", l, r, v);
  int cnt = 0, id = pos[l];
  for (int i = l; i <= r; ++i)
    if (B[id].GetHead(i) - B[id].tag == v) cnt++;
  return cnt;
}
int Query(int l, int r, int v) {
  int lid = pos[l], rid = pos[r];
  if (lid == rid) {
    return BruteForceQuery(l, r, v);
  }
  int ans = 0;
  ans += BruteForceQuery(l, B[lid].r, v);
  ans += BruteForceQuery(B[rid].l, r, v);
  for (int i = lid + 1; i <= rid - 1; ++i) {
    ans += B[i].GetSize(v + B[i].tag);
  }
  return ans;
}
int main() {
  n = read(), m = read();
  Size = sqrt(n);
  for (int i = 1; i <= n; ++i) pos[i] = (i - 1) / Size + 1;
  for (int i = 1; i <= n; ++i) a[i] = read();
  for (int i = 1; i <= pos[n]; ++i) {
    B[i].l = (i - 1) * Size + 1, B[i].r = min(i * Size, n);
    B[i].Build();
  }
  while (m--) {
    int opr = read(), l = read(), r = read(), x = read();
    if (opr == 1)
      Update(l, r, x);
    else
      printf("%d\n", Query(l, r, x));
  }
  return 0;
}
