#include <bits/stdc++.h>
using namespace std;
#define n 200005
struct Query{
int L,R,Time,noquery; // noquery = Nomor query
}query[n];
int N,Q,B,value[n],tmp[n],cnt[n],ans[n],jum,currentL,currentR,currentTime;
pair<int,int> query1[n];
bool cmp(Query x,Query y){
if(x.L/B != y.L/B) return x.L/B<y.L/B;
if(x.R/B != y.R/B) return x.R/B<y.R/B;
return x.Time < y.Time;
}
void add(int pos){
cnt[value[pos]]++;
if(cnt[value[pos]] == 1) jum++;
else if(cnt[value[pos]] == 2) jum--;
}
void rem(int pos){
cnt[value[pos]]--;
if(cnt[value[pos]] == 0) jum--;
else if(cnt[value[pos]] == 1) jum++;
}
void change(int pos){
if(query1[pos].first >= currentL && query1[pos].first <= currentR) rem(query1[pos].first);
value[query1[pos].first] = query1[pos].second;
if(query1[pos].first >= currentL && query1[pos].first <= currentR) add(query1[pos].first);
}
void reset(){
currentTime = 0;
for(int i=1;i<=N;i++) {
if(value[i] != tmp[i]){
if(i >= currentL && i <= currentR) rem(i);
value[i] = tmp[i];
if(i >= currentL && i <= currentR)
add(i);
}
}
}
int main(){
cin >> N >> Q;
B = (double)pow(N,(double)2/3); // size block , bisa N^(2/3) tapi bisa juga menggunakan konstanta sendiri
for(int i=1;i<=N;i++) cin >> value[i],tmp[i] = value[i];
int timesekarang = 0,jumlahquery2 = 0;
for(int i=1;i<=Q;i++){
int q;
cin >> q;
if(q == 1){
cin >> query1[timesekarang].first >> query1[timesekarang].second;
query1[timesekarang].first++;
timesekarang++;
}
else{
int j = jumlahquery2;
cin >> query[j].L >> query[j].R;
query[j].L++;query[j].R++;
query[j].Time = timesekarang;
query[j].noquery = j;
jumlahquery2++;
// masukin ke struct blok kiri,blok kanan,time ,indeksquery2
}
}
sort(query,query+jumlahquery2,cmp); //sort berdasarkan blok kiri, blok kanan , time
jum = 0;//jawaban sementara
currentL = 1;currentR = 0;currentTime = 0;
for(int i=0;i<jumlahquery2;i++){
//mo's
int L = query[i].L, R = query[i].R,Time = query[i].Time;
while(currentL < L) {
rem(currentL);
currentL++;
}
while(currentL > L) {
add(currentL-1);
currentL--;
}
while(currentR < R) {
add(currentR+1);
currentR++;
}
while(currentR > R) {
rem(currentR);
currentR--;
}
// kita tambahkan yang buat time
if(currentTime > Time){
reset(); //karena timenya selalu increasing maka kita dapat lakukan reset karna apabila currentTime > Time maka ia telah berpindah blok
}
while(currentTime < Time ) {
change(currentTime);
currentTime++;
}
ans[query[i].noquery] = jum; // array penyimpanan jawaban
}
for(int i=0;i<jumlahquery2;i++) cout << ans[i] << "\n";
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgojZGVmaW5lIG4gMjAwMDA1CgpzdHJ1Y3QgUXVlcnl7CglpbnQgTCxSLFRpbWUsbm9xdWVyeTsgLy8gbm9xdWVyeSA9IE5vbW9yIHF1ZXJ5Cn1xdWVyeVtuXTsKCmludCBOLFEsQix2YWx1ZVtuXSx0bXBbbl0sY250W25dLGFuc1tuXSxqdW0sY3VycmVudEwsY3VycmVudFIsY3VycmVudFRpbWU7CnBhaXI8aW50LGludD4gcXVlcnkxW25dOwoKYm9vbCBjbXAoUXVlcnkgeCxRdWVyeSB5KXsKCWlmKHguTC9CICE9IHkuTC9CKSByZXR1cm4geC5ML0I8eS5ML0I7CglpZih4LlIvQiAhPSB5LlIvQikgcmV0dXJuIHguUi9CPHkuUi9COwoJcmV0dXJuIHguVGltZSA8IHkuVGltZTsKfQp2b2lkIGFkZChpbnQgcG9zKXsKCWNudFt2YWx1ZVtwb3NdXSsrOwoJaWYoY250W3ZhbHVlW3Bvc11dID09IDEpIGp1bSsrOwoJZWxzZSBpZihjbnRbdmFsdWVbcG9zXV0gPT0gMikganVtLS07Cn0KCnZvaWQgcmVtKGludCBwb3MpewoJY250W3ZhbHVlW3Bvc11dLS07CglpZihjbnRbdmFsdWVbcG9zXV0gPT0gMCkganVtLS07CgllbHNlIGlmKGNudFt2YWx1ZVtwb3NdXSA9PSAxKSBqdW0rKzsKfQoKdm9pZCBjaGFuZ2UoaW50IHBvcyl7CglpZihxdWVyeTFbcG9zXS5maXJzdCA+PSBjdXJyZW50TCAmJiBxdWVyeTFbcG9zXS5maXJzdCA8PSBjdXJyZW50UikgcmVtKHF1ZXJ5MVtwb3NdLmZpcnN0KTsKCXZhbHVlW3F1ZXJ5MVtwb3NdLmZpcnN0XSA9IHF1ZXJ5MVtwb3NdLnNlY29uZDsKCWlmKHF1ZXJ5MVtwb3NdLmZpcnN0ID49IGN1cnJlbnRMICYmIHF1ZXJ5MVtwb3NdLmZpcnN0IDw9IGN1cnJlbnRSKSAJYWRkKHF1ZXJ5MVtwb3NdLmZpcnN0KTsKfQoKdm9pZCByZXNldCgpewoJY3VycmVudFRpbWUgPSAwOwoJZm9yKGludCBpPTE7aTw9TjtpKyspIHsKCQlpZih2YWx1ZVtpXSAhPSB0bXBbaV0peyAKCQkJaWYoaSA+PSBjdXJyZW50TCAmJiBpIDw9IGN1cnJlbnRSKSByZW0oaSk7CgkJCXZhbHVlW2ldID0gdG1wW2ldOwoJCQlpZihpID49IGN1cnJlbnRMICYmIGkgPD0gY3VycmVudFIpCgkJCWFkZChpKTsKCQl9Cgl9Cn0KCmludCBtYWluKCl7CgljaW4gPj4gTiA+PiBROwoJQiA9IChkb3VibGUpcG93KE4sKGRvdWJsZSkyLzMpOyAvLyBzaXplIGJsb2NrICwgYmlzYSBOXigyLzMpIHRhcGkgYmlzYSBqdWdhIG1lbmdndW5ha2FuIGtvbnN0YW50YSBzZW5kaXJpIAoJZm9yKGludCBpPTE7aTw9TjtpKyspIGNpbiA+PiB2YWx1ZVtpXSx0bXBbaV0gPSB2YWx1ZVtpXTsKCWludCB0aW1lc2VrYXJhbmcgPSAwLGp1bWxhaHF1ZXJ5MiA9IDA7CgkKCWZvcihpbnQgaT0xO2k8PVE7aSsrKXsKCQlpbnQgcTsKCQljaW4gPj4gcTsKCQlpZihxID09IDEpewoJCQljaW4gPj4gcXVlcnkxW3RpbWVzZWthcmFuZ10uZmlyc3QgPj4gcXVlcnkxW3RpbWVzZWthcmFuZ10uc2Vjb25kOwoJCQlxdWVyeTFbdGltZXNla2FyYW5nXS5maXJzdCsrOwoJCQl0aW1lc2VrYXJhbmcrKzsKCQl9CgkJZWxzZXsKCQkJaW50IGogPSBqdW1sYWhxdWVyeTI7CgkJCWNpbiA+PiBxdWVyeVtqXS5MID4+IHF1ZXJ5W2pdLlI7CgkJCXF1ZXJ5W2pdLkwrKztxdWVyeVtqXS5SKys7CgkJCXF1ZXJ5W2pdLlRpbWUgPSB0aW1lc2VrYXJhbmc7CQkKCQkJcXVlcnlbal0ubm9xdWVyeSA9IGo7CgkJCWp1bWxhaHF1ZXJ5MisrOwoJCQkvLyBtYXN1a2luIGtlIHN0cnVjdCBibG9rIGtpcmksYmxvayBrYW5hbix0aW1lICxpbmRla3NxdWVyeTIKCQl9Cgl9Cglzb3J0KHF1ZXJ5LHF1ZXJ5K2p1bWxhaHF1ZXJ5MixjbXApOyAvL3NvcnQgYmVyZGFzYXJrYW4gYmxvayBraXJpLCBibG9rIGthbmFuICwgdGltZQoJanVtID0gMDsvL2phd2FiYW4gc2VtZW50YXJhCgljdXJyZW50TCA9IDE7Y3VycmVudFIgPSAwO2N1cnJlbnRUaW1lID0gMDsKCWZvcihpbnQgaT0wO2k8anVtbGFocXVlcnkyO2krKyl7CgkJLy9tbydzCgkJaW50IEwgPSBxdWVyeVtpXS5MLCBSID0gcXVlcnlbaV0uUixUaW1lID0gcXVlcnlbaV0uVGltZTsKCQl3aGlsZShjdXJyZW50TCA8IEwpIHsKCQkJcmVtKGN1cnJlbnRMKTsKCQkgCWN1cnJlbnRMKys7CgkJfQoJCXdoaWxlKGN1cnJlbnRMID4gTCkgewoJCQlhZGQoY3VycmVudEwtMSk7CgkJCWN1cnJlbnRMLS07CgkJfQoJCXdoaWxlKGN1cnJlbnRSIDwgUikgewoJCSAJYWRkKGN1cnJlbnRSKzEpOwoJCSAJY3VycmVudFIrKzsKCQl9CgkJd2hpbGUoY3VycmVudFIgPiBSKSB7CgkJCXJlbShjdXJyZW50Uik7CgkJIAljdXJyZW50Ui0tOwoJCX0KCQkvLyBraXRhIHRhbWJhaGthbiB5YW5nIGJ1YXQgdGltZQoJCWlmKGN1cnJlbnRUaW1lID4gVGltZSl7CgkJCXJlc2V0KCk7IC8va2FyZW5hIHRpbWVueWEgc2VsYWx1IGluY3JlYXNpbmcgbWFrYSBraXRhIGRhcGF0IGxha3VrYW4gcmVzZXQga2FybmEgYXBhYmlsYSBjdXJyZW50VGltZSA+IFRpbWUgbWFrYSBpYSB0ZWxhaCBiZXJwaW5kYWggYmxvawoJCX0KCQl3aGlsZShjdXJyZW50VGltZSA8IFRpbWUgKSB7CgkJCWNoYW5nZShjdXJyZW50VGltZSk7CgkJCWN1cnJlbnRUaW1lKys7CgkJfQoJCWFuc1txdWVyeVtpXS5ub3F1ZXJ5XSA9IGp1bTsgLy8gYXJyYXkgcGVueWltcGFuYW4gamF3YWJhbgoJfQoJZm9yKGludCBpPTA7aTxqdW1sYWhxdWVyeTI7aSsrKSBjb3V0IDw8IGFuc1tpXSA8PCAiXG4iOwp9