RT
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt")
#include <bits/stdc++.h>
using namespace std;
#define _f(i, a, b) for (int i = a; i <= b; ++i)
#define _d(i, a, b) for (int i = a; i >= b; --i)
using pii = pair<int, int>;
using ll = long long;
#define fi first
#define se second
static constexpr int N = 1e5 + 5;
int n, m, v[N << 1], cnt, pos[N << 1], lv, h[N], pre[N];
int opt[N], l[N], r[N], x[N];
struct cdq { int pre, i, t, val, type; } p[N << 4];
namespace odt {
struct node {
int l, r; mutable int v;
node(const int &ll, const int &rr, const int &vv) { l = ll, r = rr, v = vv; }
bool operator<(const node &x) const {
return l < x.l;
}
} ;
set<node> t;
set<pii> col[N << 1];
auto split(int x) {
if(x > n) return t.end();
auto it = --t.upper_bound(node{x, 0, 0});
if(it->l == x) return it;
int l = it->l, r = it->r, v = it->v;
t.erase(it);
col[v].erase(make_pair(l, r));
col[v].insert(make_pair(l, x - 1)), col[v].insert(make_pair(x, r));
t.insert(node(l, x - 1, v));
return t.insert(node(x, r, v)).fi;
}
void assign(int l, int r, int v, int tm) {
auto upd = [](int &pre, int to, int x, int tt) {
if(pre != to) {
p[++cnt] = (cdq){pre, x, tt, -1, 1};
pre = to;
p[++cnt] = (cdq){pre, x, tt, -1, 1};
}
return ;
} ;
auto itr = split(r + 1), itl = split(l);
for(; itl != itr; ++itl) {
int x = itl -> l, y = itl -> r, k = itl -> v;
col[k].erase(make_pair(x, y));
if(x == l) {
int to = (--(col[k].upper_bound(make_pair(x, 0)))) -> se;
upd(pre[x], to, x, tm);
} else {
upd(pre[x], x - 1, x, tm);
}
int fr = col[k].upper_bound(make_pair(y, 0)) -> fi;
int to = (--col[k].lower_bound(make_pair(l, 0))) -> se;
if(to >= 1 && fr <= n && fr > r) upd(pre[fr], to, fr, tm);
}
int x = col[v].upper_bound(make_pair(r, 0)) -> first;
if(x <= n) upd(pre[x], r, x, tm);
col[v].insert(make_pair(l, r));
t.erase(itl, itr), t.insert(node(l, r, v));
}
}
namespace BIT {
int f[N << 1];
int lowbit(int x) { return x & (-x); }
void add(int x, int k) {
while(x <= lv) f[x] += k, x += lowbit(x);
}
int query(int x) {
int ret = 0;
while(x) ret += f[x], x -= lowbit(x);
return ret;
}
int query(int l, int r) { return query(r) - query(l - 1); }
}
bool cmp(cdq x, cdq y) {
return x.pre < y.pre;
}
void CDQ(int l, int r) {
if(l == r) return ;
int mid = (l + r) >> 1;
CDQ(l, mid), CDQ(mid + 1, r);
sort(p + l, p + mid + 1, cmp);
sort(p + mid + 1, p + r + 1, cmp);
int i = mid + 1, j = l;
while(i <= r) {
while(j <= mid && p[j].pre < p[i].pre) {
if(p[j].type == 1) BIT::add(p[j].i, p[j].val);
++j;
}
if(p[i].type == 2) p[i].val = BIT::query(p[i].pre, p[i].i);
++i;
}
_f(k, l, j - 1) if(p[k].type == 1) BIT::add(p[k].i, -p[k].val);
}
void solve() {
cin >> n >> m, cnt = n;
_f(i, 1, n) cin >> v[i], h[i] = v[i], p[i] = (cdq){0, i, 0, 1, 1};
_f(i, 1, m) {
cin >> opt[i] >> l[i] >> r[i];
if(opt[i] == 1) cin >> x[i], v[++cnt] = x[i];
}
sort(v + 1, v + cnt + 1), lv = unique(v + 1, v + cnt + 1) - v - 1;
_f(i, 1, n) h[i] = lower_bound(v + 1, v + lv + 1, h[i]) - v;
_f(i, 1, lv) odt::col[i].insert(make_pair(0, 0)), odt::col[i].insert(make_pair(n + 1, 0));
_f(i, 1, n) odt::t.insert((odt::node){i, i, h[i]}), odt::col[h[i]].insert(make_pair(i, i));
_f(i, 1, m) if(opt[i] == 2) x[i] = lower_bound(v + 1, v + lv + 1, x[i]) - v;
_f(i, 1, n) p[i].pre = pre[i] = pos[h[i]], pos[h[i]] = i;
cnt = n;
_f(i, 1, m) {
if(opt[i] == 1) odt::assign(l[i], r[i], x[i], i);
else p[++cnt] = (cdq){l[i], r[i], i, 0, 2};
}
CDQ(1, cnt);
sort(p + 1, p + cnt + 1, [&](cdq x, cdq y) { return x.t < y.t; });
_f(i, 1, cnt) if(p[i].type == 2) cout << p[i].val << '\n';
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("1.txt", "r", stdin);
freopen("2.txt", "w", stdout);
#endif
solve();
return 0;
}
// by zzzcr.