#include <bits/stdc++.h>
using namespace std;
int a[100001], parent[100001], sz[100001], p[(100001 / 320 + 1)],
    mx[(100001 / 320 + 1)], h[(100001 / 320 + 1)][100001];
bool isBlockDirty[(100001 / 320 + 1)];
int Find(int i) {
  if (i == parent[i])
    return i;
  else {
    parent[i] = Find(parent[i]);
    return parent[i];
  }
}
void Move(int k, int s, int d) {
  int h1 = h[k][s], h2 = h[k][d];
  h[k][s] = -1;
  if (h1 == -1) return;
  if (h2 == -1) {
    a[h1] += (d - s);
    h[k][d] = h1;
  } else {
    parent[h1] = h2;
    sz[h2] += sz[h1];
  }
}
void Print(int n) {
  for (int i = 0; i < n; ++i) {
    int j = Find(i);
    int k = i / 320;
    printf("%d %d %d %d %d %d\n", i, j, a[j], p[k], mx[k], a[j] + p[k]);
  }
  printf("\n\n");
}
void DestroyBlockDSU(int k) {
  if (isBlockDirty[k]) return;
  for (int l = k * 320, r = min(l + 320, 100001), i = l; i < r; ++i) {
    int j = Find(i);
    a[i] = a[j];
    h[k][a[i]] = -1;
  }
  for (int l = k * 320, r = min(l + 320, 100001), i = l; i < r; ++i) {
    a[i] += p[k];
    parent[i] = i;
    sz[i] = 1;
  }
  mx[k] = 0;
  p[k] = 0;
  isBlockDirty[k] = 1;
}
void BuildBlockDSU(int k) {
  mx[k] = 0;
  p[k] = 0;
  for (int l = k * 320, r = min(l + 320, 100001), i = l; i < r; ++i) {
    if (h[k][a[i]] == -1)
      h[k][a[i]] = i;
    else {
      int j = h[k][a[i]];
      parent[i] = j;
      ++sz[j];
    }
    mx[k] = max(mx[k], a[i]);
  }
  isBlockDirty[k] = 0;
}
void PreProcess(int n) {
  for (int i = 0; i < (100001 / 320 + 1); ++i)
    for (int j = 0; j < 100001; ++j) h[i][j] = -1;
  for (int k = 0; k * 320 < n; ++k) isBlockDirty[k] = 1;
  for (int i = 0; i < n; ++i) {
    parent[i] = i;
    sz[i] = 1;
  }
}
void UpdateInBlock(int k, int l, int r, int x) {
  DestroyBlockDSU(k);
  for (int i = l; i <= r; ++i) {
    if (a[i] > x) a[i] -= x;
  }
}
void UpdateBlock(int k, int x) {
  if (isBlockDirty[k]) BuildBlockDSU(k);
  if (x >= mx[k]) return;
  if (2 * x < mx[k]) {
    for (int l = 1 - p[k], r = x - p[k], i = l; i <= r; ++i) Move(k, i, i + x);
    p[k] -= x;
    mx[k] -= x;
  } else {
    for (int l = x + 1 - p[k], r = mx[k] - p[k], i = l; i <= r; ++i)
      Move(k, i, i - x);
    int _mx = x - p[k];
    for (; h[k][_mx] == -1; --_mx)
      ;
    mx[k] = _mx + p[k];
  }
}
void Update(int l, int r, int x) {
  int lk = l / 320, rk = r / 320;
  if (lk == rk)
    UpdateInBlock(lk, l, r, x);
  else {
    for (int k = lk; k <= rk; ++k) {
      int i = max(k * 320, l), j = min((k + 1) * 320 - 1, r);
      if (j - i + 1 < 320)
        UpdateInBlock(k, i, j, x);
      else
        UpdateBlock(k, x);
    }
  }
}
int QueryInBlock(int k, int l, int r, int x) {
  int ans = 0;
  for (int i = l; i <= r; ++i) {
    int j = Find(i);
    ans += (a[j] + p[k] == x);
  }
  return ans;
}
int QueryBlock(int k, int x) {
  if (x - p[k] >= 100001) return 0;
  if (isBlockDirty[k]) BuildBlockDSU(k);
  int i = h[k][x - p[k]];
  if (i == -1) return 0;
  int ans = sz[i];
  return ans;
}
int Query(int l, int r, int x) {
  int lk = l / 320, rk = r / 320;
  if (lk == rk)
    return QueryInBlock(lk, l, r, x);
  else {
    int ans = 0;
    for (int k = lk; k <= rk; ++k) {
      int i = max(k * 320, l), j = min((k + 1) * 320 - 1, r);
      if (j - i + 1 < 320)
        ans += QueryInBlock(k, i, j, x);
      else
        ans += QueryBlock(k, x);
    }
    return ans;
  }
}
int main() {
  int n, q;
  scanf("%d%d", &n, &q);
  for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
  PreProcess(n);
  while (q--) {
    int t, l, r, x;
    scanf("%d%d%d%d", &t, &l, &r, &x);
    --l, --r;
    if (t == 1) {
      Update(l, r, x);
    } else
      printf("%d\n", Query(l, r, x));
  }
  return 0;
}
