#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int n, m;
int a[1000010];//原数组
int op[500010];//操作类型(以下三个如题意)
int l[500010];
int r[500010];
int x[500010];
int ans[500010];//对于操作2的答案
int id[200010];//将数映射的值
int fa[200010];//并查集祖先关系
int size[200010];//并查集大小
int value[200010];//原值
int L, R, Size; //单块左界,右界,块大小
int Find(int x)
{
if (x == fa[x])
{
return fa[x];
}
fa[x] = Find(fa[x]);
return fa[x];
}
void Merge(int x, int y)
{
if (id[y])
{
fa[id[x]] = id[y];
}
else
{
id[y] = id[x];
value[id[y]] = y;
}
size[y] += size[x];
id[x] = 0;
size[x] = 0;
return;
}
int tag;//整体减法tag
void Delete()
{
for (int i = L; i <= R; i++)
{
a[i] = value[Find(i)];
id[a[i]] = 0;
size[a[i]] = 0;
a[i] -= tag;
}
for (int i = L; i <= R; i++)
{
fa[i] = 0;
}
tag = 0;
return;
}
int maxx;
void Remake()
{
maxx = 0;
for (int i = L; i <= R; i++)
{
if (!id[a[i]])
{
id[a[i]] = i;
value[i] = a[i];
fa[i] = i;
}
else
{
fa[i] = id[a[i]];
}
size[a[i]]++;
maxx = max(maxx, a[i]);
}
return;
}
void Allupdate(int x)
{
if (maxx - tag >= (x << 1))
{
for (int i = tag + 1; i <= tag + x; i++)
{
if (id[i])
{
Merge(i, i + x);
}
}
tag += x;
}
else
{
for (int i = maxx; i > tag + x; i--)
{
if (id[i])
{
Merge(i, i - x);
}
}
maxx = min(maxx, tag + x);
}
return;
}
void Partupdate(int ll, int rr, int x)
{
if (ll > rr)
{
return;
}
Delete();
for (int i = ll; i <= rr; i++)
{
if (a[i] > x)
{
a[i] -= x;
}
}
Remake();
return;
}
int Allquery(int x)
{
if (x + tag > 200005)
{
return 0;
}
return size[x + tag];
}
int Partquery(int ll, int rr, int x)
{
int ans = 0;
for (int i = ll; i <= rr; i++)
{
if (value[Find(i)] - tag == x)
{
ans++;
}
}
return ans;
}
int pos[1000010], bl[1100], br[1100];
//int zero_sum[1000010];
int main()
{
scanf("%d%d", &n, &m);
Size = 1145;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
// zero_sum[i] = zero_sum[i - 1] + (a[i] == 0);
}
for (int i = 1; i <= m; i++)
{
scanf("%d%d%d%d", &op[i], &l[i], &r[i], &x[i]);
}
for (register int i = 1; i <= n; i++)
pos[i] = (i - 1) / Size + 1;
for (register int i = 1; i <= pos[n]; i++)
{
bl[i] = (i - 1) * Size + 1;
br[i] = min(i * Size, n);
}
for (int i = 1; i <= pos[n]; i++)
{
L = bl[i];
R = br[i];
Remake();
for (int j = 1; j <= m; j++)
{
if (op[j] == 1)
{
if (l[j] <= L && r[j] >= R)
{
Allupdate(x[j]);
}
else
{
Partupdate(max(l[j], L), min(r[j], R), x[j]);
}
}
else
{
// if (x[j] == 0)
// {
// ans[j] += zero_sum[min(R, r[j])] - zero_sum[max(L, l[j]) - 1];
// continue;
// }
if (l[j] <= L && r[j] >= R)
{
ans[j] += Allquery(x[j]);
}
else
{
ans[j] += Partquery(max(l[j], L), min(r[j], R), x[j]);
}
}
}
Delete();
}
for (int i = 1; i <= m; i++)
{
if (op[i] == 2)
{
printf("%d\n", ans[i]);
}
}
return 0;
}
要么全WA要么MLE+RE+TLE