#include <bits/stdc++.h>
using namespace std;
const int Imx = 2147483647;
const long long Lbig = 2e18;
const int mod = 1e9 + 7;
struct fastio {
  char s[100000];
  int it, len;
  fastio() { it = len = 0; }
  inline char get() {
    if (it < len) return s[it++];
    it = 0;
    len = fread(s, 1, 100000, stdin);
    if (len == 0)
      return EOF;
    else
      return s[it++];
  }
  bool notend() {
    char c = get();
    while (c == ' ' || c == '\n') c = get();
    if (it > 0) it--;
    return c != EOF;
  }
} _buff;
inline long long getnum() {
  long long r = 0;
  bool ng = 0;
  char c;
  c = _buff.get();
  while (c != '-' && (c < '0' || c > '9')) c = _buff.get();
  if (c == '-') ng = 1, c = _buff.get();
  while (c >= '0' && c <= '9') r = r * 10 + c - '0', c = _buff.get();
  return ng ? -r : r;
}
template <class T>
inline void putnum(T x) {
  if (x < 0) putchar('-'), x = -x;
  register short a[20] = {}, sz = 0;
  while (x) a[sz++] = x % 10, x /= 10;
  if (sz == 0) putchar('0');
  for (int i = sz - 1; i >= 0; i--) putchar('0' + a[i]);
}
inline char getreal() {
  char c = _buff.get();
  while (c <= 32) c = _buff.get();
  return c;
}
const int block_cnt = 400;
const int block_size = 400;
const int mxv = 100005;
struct BLOCK {
  int n;
  int cnt[mxv + 233], f[mxv + block_size + 233];
  int lazy, mx;
  int gf(int x) { return f[x] == x ? x : f[x] = gf(f[x]); }
  void init(int ia[], int N) {
    mx = mxv;
    for (int i = 0; i < mxv + block_size + 233; i++) f[i] = i;
    memset(cnt, 0, sizeof(cnt));
    lazy = 0;
    n = N;
    for (int i = 1; i <= n; i++) f[mxv + i] = ia[i], cnt[ia[i]]++;
  }
  void modify(int x, int y, int v) {
    if (x == -1) x = 1;
    if (y == -1) y = n;
    assert(1 <= x && x <= y && y <= n);
    v += lazy;
    for (int i = x; i <= y; i++) {
      int cur = gf(mxv + i);
      if (cur > v) {
        cnt[cur]--;
        cur = cur - v + lazy;
        cnt[cur]++;
        f[mxv + i] = cur;
      }
    }
  }
  void modify_all(int v) {
    v += lazy;
    if (v <= lazy || v >= mx) return;
    int mid = lazy + mx >> 1;
    if (v <= mid) {
      for (int i = lazy + 1; i <= v; i++) {
        int nxt = i - lazy + v;
        assert(nxt <= mx);
        f[i] = nxt;
        cnt[nxt] += cnt[i];
        cnt[i] = 0;
      }
      lazy = v;
    } else {
      for (int i = mx; i > v; i--) {
        int nxt = i - v + lazy;
        assert(nxt <= v);
        f[i] = nxt;
        cnt[nxt] += cnt[i];
        cnt[i] = 0;
      }
      mx = v;
    }
  }
  int query(int x, int y, int v) {
    if (x == -1) x = 1;
    if (y == -1) y = n;
    assert(1 <= x && x <= y && y <= n);
    int ret = 0;
    for (int i = x; i <= y; i++) ret += gf(mxv + i) == v + lazy;
    return ret;
  }
  int query_all(int v) { return v + lazy <= 100000 ? cnt[v + lazy] : 0; }
} B[block_cnt];
int n, m, a[100111], iid[100111];
int main() {
  n = getnum(), m = getnum();
  for (int i = 1; i <= n; i++) a[i] = getnum();
  for (int i = 1; i <= n; i += block_size) {
    int r = min(n, i + block_size - 1);
    B[(i - 1) / block_size].init(a + i - 1, r - i + 1);
    for (int j = i; j <= r; j++) iid[j] = j - i + 1;
  }
  for (int i = 1; i <= m; i++) {
    int op, x, y, v;
    op = getnum(), x = getnum();
    y = getnum(), v = getnum();
    assert(v > 0 && v <= 100000);
    if (op == 1) {
      int lid = (x - 1) / block_size;
      int rid = (y - 1) / block_size;
      if (lid == rid)
        B[lid].modify(iid[x], iid[y], v);
      else {
        B[lid].modify(iid[x], -1, v);
        B[rid].modify(-1, iid[y], v);
        for (int i = lid + 1; i < rid; i++) B[i].modify_all(v);
      }
    } else {
      int ans = 0;
      int lid = (x - 1) / block_size;
      int rid = (y - 1) / block_size;
      if (lid == rid)
        ans = B[lid].query(iid[x], iid[y], v);
      else {
        ans += B[lid].query(iid[x], -1, v);
        ans += B[rid].query(-1, iid[y], v);
        for (int i = lid + 1; i < rid; i++) ans += B[i].query_all(v);
      }
      putnum(ans), putchar('\n');
    }
  }
  return 0;
}
