#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;   }