#include <stdio.h>
#include <bits/stdc++.h>

using namespace std;
using ll = long long;

struct union_find {
  int n;
  vector<int> fa;

  union_find(int s) {
    n = s + 1;
    reset();
  }

  void reset() {
    fa.assign(n, 0);
  }

  int find(int x) {
    return fa[x] ? fa[x] = find(fa[x]) : x;
  }

  void unite(int x, int y, int b, auto& blocks) {
    x = find(x);
    y = find(y);
    if(x != y) {
      fa[y] = x;
      blocks[b][x] += blocks[b][y];
      blocks[b][y] = 0;
    }
  }
};

struct sqrt_decomposition {
  int n;
  int blks;
  int blk_sz;
  vector<int> a;
  vector<int> mx, diff;
  vector<union_find> dsu;
  vector<vector<int>> blocks;

  sqrt_decomposition(vector<int>& original_array) {
    a.swap(original_array);
    build();
  }

  void build() {
    n = a.size();
    blk_sz = 1000;
    blks = (n + blk_sz - 1) / blk_sz;

    int MX = 100 * 1000;
    blocks.assign(blks, vector<int>(MX + 1));
    dsu.assign(blks, union_find(MX + 1));
    diff.assign(blks, 0);
    mx.assign(blks, 0);

    for(int i = 0; i < n; ++i) {
      blocks[i/blk_sz][a[i]]++;
      mx[i/blk_sz] = max(mx[i/blk_sz], a[i]);
    }
  }

  void rebuild(int b) {
    int l = b * blk_sz;
    int r = min(l + blk_sz - 1, n - 1);

    for(int i = l; i <= r; ++i)
      a[i] = dsu[b].find(a[i]);
  }

  void rebuild_update(int b, int l, int r, int x) {
    rebuild(b);
    for(int i = b * blk_sz, lim = min(i+blk_sz, n); i < lim; ++i) {
      if(i < l) continue;
      if(r < i) break;

      if(a[i] - diff[b] > x) {
        blocks[b][a[i]]--;
        a[i] -= x;
        blocks[b][a[i]]++;
      }
    }
  }

  void update(int l, int r, int x) {
    int bl = l / blk_sz;
    int br = r / blk_sz;

    rebuild_update(bl, l, r, x);
    if(bl != br)
      rebuild_update(br, l, r, x);

    for(int b = bl+1; b < br; ++b) {
      if(x + x <= mx[b]) {
        for(int i = 1; i <= x; ++i)
          dsu[b].unite(i + x + diff[b], i + diff[b], b, blocks);
        diff[b] += x;
        mx[b] -= x;
      } else if(x < mx[b]) {
        for(int i = x+1; i <= mx[b]; ++i)
          dsu[b].unite(i + diff[b], i - x + diff[b], b, blocks);       
        mx[b] = x;
      }
    }
  }

  int query(int l, int r, int x) {
    int cnt = 0;
    while(l <= r) {
      if(l % blk_sz == 0 && (l + blk_sz - 1) <= r) {
        cnt += blocks[l/blk_sz][x + diff[l/blk_sz]];
        l += blk_sz;
      } else {
        int b = l / blk_sz;
        rebuild(b);
        int lim = min(l + (blk_sz - (l % blk_sz)) - 1, r);
        while(l <= lim)
          cnt += (a[l++] - diff[b] == x);
      }
    }
    return cnt;
  }
};

int main() {
  cin.tie(0);
  cin.sync_with_stdio(0);

  int n, m;
  cin >> n >> m;

  vector<int> a(n);
  for(int i = 0; i < n; ++i)
    cin >> a[i];

  sqrt_decomposition sd(a);

  while(m--) {
    int t, l, r, x;
    cin >> t >> l >> r >> x;

    if(t & 1)
      sd.update(l-1, r-1, x);
    else
      cout << sd.query(l-1, r-1, x) << "\n";
  }
}