#include <time.h>

#include <stdlib.h>
#include <cstdint>
#include <cassert>
#include <algorithm>
#include <functional>
#include <iostream>
#include <limits>
#include <cstdint>
#include <cassert>
#include <algorithm>
#include <functional>
#include <iostream>
#include <limits>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
#include <numeric>
#include <cmath>
#include <bitset>
#include <iterator>
#include <deque>
#include <string>
#include <queue>

using namespace std;
const int64_t INF=10000000000000000;
#include <cstdint>
#include <cassert>
#include <algorithm>
#include <functional>
#include <iostream>
#include <limits>

class SegmentTree_sum {
public:
	SegmentTree_sum(int64_t size,const int64_t *d);
	SegmentTree_sum(const SegmentTree_sum& t);
	SegmentTree_sum& operator=(const SegmentTree_sum& t);
	int64_t calcsum(const int64_t a,const int64_t b) const;//[a,b]の間の最小値
	void change(const int64_t address,const int64_t value);
	virtual ~SegmentTree_sum();
private:
	int64_t max_depth;
	int64_t calcsum(const int64_t a,const int64_t b,const int64_t ptr,const int64_t range_min,const int64_t range_max) const;
	//calcminからよばれる内部処理 [a,b]について、配列番号ptrのものを探索 配列番号ptrが指す範囲は、[range_min,range_max]
	int64_t size;
	int64_t *data;
};
SegmentTree_sum::SegmentTree_sum(int64_t dsize,const int64_t *d) {

	// TODO 自動生成されたコンストラクター・スタブ
	for(int i=63;i>=0;i--){
		if(dsize&((uint64_t)1<<i)){
			max_depth = i+1;
			break;
		}
	}
	this->size = ((uint64_t)1<<(max_depth));
	data = new int64_t[2*size-1];
	for(int64_t i=0;i<dsize;i++){
		data[size-1+i]=d[i];
	}
	for(int64_t i=dsize;i<size;i++){
		data[size-1+i]=0;
	}
	for(int64_t i=size-2;i>=0;i--){
		data[i]=data[2*i+1]+data[2*i+2];
	}
}
SegmentTree_sum::SegmentTree_sum(const SegmentTree_sum& t){
	if(&t==this){
		max_depth = 1;
		size = 1;
		data = new int64_t[1];
		data[0]=0;
	}else{
		max_depth = t.max_depth;
		size = t.size;
		data = new int64_t[2*size-1];
		for(int64_t i=0;i<(2*size-1);i++){
			data[i]=t.data[i];
		}
	}
}
SegmentTree_sum& SegmentTree_sum::operator=(const SegmentTree_sum& t){
	if(&t!=this){
		delete[] data;
		max_depth = t.max_depth;
		size = t.size;
		data = new int64_t[2*size-1];
		for(int64_t i=0;i<(2*size-1);i++){
			data[i]=t.data[i];
		}
	}
	return *this;
}
int64_t SegmentTree_sum::calcsum(const int64_t a,const int64_t b) const{
	return calcsum(a,b,0,0,size-1);
}
int64_t SegmentTree_sum::calcsum(const int64_t a,const int64_t b,const int64_t ptr,const int64_t range_min,const int64_t range_max) const{
	if(a<=range_min&&b>=range_max){
		return data[ptr];
	}else{
		int64_t border = (range_max+range_min-1)/2;
		if(b<=border){
			return calcsum(a,b,2*ptr+1,range_min,border);
		}else if(a>=border+1){
			return calcsum(a,b,2*ptr+2,border+1,range_max);
		}else{
			return calcsum(a,border,ptr*2+1,range_min,border)+calcsum(border+1,b,ptr*2+2,border+1,range_max);
		}
	}
}
void SegmentTree_sum::change(const int64_t address,const int64_t value){
	data[address + size -1]=value;
	int64_t i=address+size-1;
	do{
		i=(i-1)/2;
		data[i]=data[2*i+1]+data[2*i+2];
	}while(i!=0);
}
SegmentTree_sum::~SegmentTree_sum() {
	// TODO Auto-generated destructor stub
	delete[] data;
}

int main(){
	int n;
	cin>>n;
	string s;
	cin>>s;
	vector<SegmentTree_sum> alphabets;
	for(int i1=0;i1<26;i1++){
		int64_t *temp = new int64_t[n];
		for(int64_t i1=0;i1<n;i1++){
			temp[i1]=0;
		}
		alphabets.push_back(SegmentTree_sum(n,temp));
	}
	for(int64_t i1=0;i1<n;i1++){
		char t=s[i1];
		alphabets[t-'a'].change(i1,1);
	}
	int64_t q;
	cin>>q;
	for(int64_t i1=0;i1<q;i1++){
		int query_type;
		cin>>query_type;
		if(query_type==1){
			int64_t i;
			char c;
			cin>>i>>c;
			i=i-1;
			if(s[i]!=c){
				alphabets[s[i]-'a'].change(i,0);
				s[i]=c;
				alphabets[s[i]-'a'].change(i,1);
			}
		}else{
			int64_t l,q;
			cin>>l>>q;
			int64_t ans=0;
			for(int64_t i2=0;i2<26;i2++){
				if(alphabets[i2].calcsum(l-1,q-1)!=0){
					ans++;
				}
			}
			cout<<ans<<endl;
		}
	}

}


Measured memory_bytes: 352764