#include <bits/stdc++.h>
using ll = long long;
using namespace std;
#define rep(i,n) for(int i=0, i##_len=(int)(n); i<i##_len; i++)
#define reps(i,n) for(int i=1 , i##_len=(int)(n);i<=i##_len;i++)
#define rrep(i,n) for(int i=((int)(n)-1);i>=0;i--)
#define rreps(i,n) for(int i=((int)(n));i>0;i--)
#define repi(i,x) for(auto i=(x).begin(),i##_fin=(x).end();i!=i##_fin;i++)
#define all(x) (x).begin(), (x).end()
#define input(array) repi(array##_itr, array) { cin >> *(array##_itr); }
#define F first
#define S second
#define mp make_pair
#define mt make_tuple
#define pb push_back
#define eb emplace_back
string solve(bool a) { return ((a) ? "Yes" : "No"); }
typedef vector<int> Vi;
typedef vector<Vi> VVi;
typedef pair<int , int> Pi;
typedef vector<Pi> VPi;
typedef vector<long long> V;
typedef vector<V> VV;
typedef pair<long long , long long> P;
typedef vector<P> VP;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1;} return 0;}
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1;} return 0;}
const long long INFLL = 1LL<<60;
const int INF = 1<<30;
const double PI=acos(-1);
//SegmentTree
template<class T>class SegmentTree{
	vector<T> seg;
	function<T(T, T)> func;
	/*func:ex)
	function<int(int,int)>down=[](int a,int b){return min(a,b);};
	*/
private:
	T findquary(int left,int right,int index,int atStart,int atStop){
		if ((left <= atStart) and (atStop <= right)){ //対象範囲に完全に囲まれる
			return seg[index];
		}if((atStop <= left) or ( right < atStart)){ //対象範囲に全く関わらない
			return init;
		}if (index >= size){ //範囲外・子がいない
			return seg[index];
		}
		//対象に一部が含まれる
		T aL=findquary(left, right, index * 2, atStart, atStart + (atStop - atStart) / 2);
		T aR= findquary(left, right, index * 2 +1,  atStart +(atStop - atStart) / 2, atStop);
		return func(aL,aR);
	}
	T upquary(int index){ //q1
		return func(seg[index],seg[index+1]);
	}
	int bin_quary(int left,int right,int index,int atStart,int atStop,T value,bool leftFirst){
		if(found==false){
			clean();
		} //fprintf(stderr,"%d %d %d %d %d %d %d\n",left,right,index,atStart,atStop,value,leftFirst);
		int res = (leftFirst ? (size * 2) : (size-1)) ; //初期値
		if (index >= size * 2){ //範囲外
			return (leftFirst ? (size * 2) : (0));
		} //fprintf(stderr,"seg[%d]:%lld\n",index,seg[index]);
		if(index >=size){ //子がいない
			if(seg[index] <=value){
				return index;
			}else{
				return (leftFirst ? (size * 2) : (0));
			}
		} //fprintf(stderr, "(seg[%d]:%lld, seg[%d]:%lld)\n", index*2, seg[index*2],(index*2)+1,seg[(index*2)+1]);
		if ((left <= atStart) and (atStop <= right)){ //完全に囲まれる
			if(leftFirst){
				if(seg[index*2]<= value){
					return bin_quary(left,right,index*2,atStart,atStart+(atStop-atStart)/2,value,true);
				}
				if(seg[index*2+1]<=value){
					return bin_quary(left, right, index * 2+1, atStart + (atStop - atStart) / 2,atStop, value, true);
				}
				return res;
			}else{
				if (seg[index * 2 + 1] <= value){
					return bin_quary(left, right, index * 2+1, atStart + (atStop - atStart) / 2, atStop, value, false);
				}
				if (seg[index * 2] <= value){
					return bin_quary(left, right, index * 2, atStart, atStart + (atStop - atStart) / 2, value, false);
				}
				return res;
			}
		}
		if ((atStop <= left) or (right < atStart)){ //全くかかわらない
			return (leftFirst?(size*2):(0));
		}
		//一部が含まれる
		if (leftFirst){
			if (seg[index * 2] <= value){
				chmin(res, bin_quary(left, right, index * 2, atStart, atStart + (atStop - atStart) / 2, value, true));
			}
			if (seg[index * 2 + 1] <= value){
				chmin(res, bin_quary(left, right, index * 2+1, atStart + (atStop - atStart) / 2, atStop, value, true));
			}
			}else{
				if (seg[index * 2 + 1] <= value){
					chmax(res, bin_quary(left, right, index * 2+1, atStart + (atStop - atStart) / 2, atStop, value, false));
				}
			if (seg[index * 2] <= value){
				chmax(res,bin_quary(left, right, index * 2, atStart, atStart + (atStop - atStart) / 2, value, false));
			}
		}
	return res;
	}
public:
	int size; //size of segmenttree
	T init; //unit
	bool found=false; //find query done
	//constructor
	SegmentTree(int _legth, function<T(T, T)> _func, T _init = 0 ){
		size=1;
		func = _func;
		init=_init;
		while(size <=_legth){
			size<<=1;
		}
		seg.assign(size<<1,init);
	}
	T get(int index){
		return seg[size+index];
	}
	void show(){
		rep(i,size*2){
			clog<<seg[i]<<" ";
		}
		clog<<endl;
	}
	void clean(){
		found=true;
		for(int i=(size<<1)-2;i>=2;i-=2){
			seg[i/2]=upquary(i);
		}
	}
	//指定範囲内で、value以下となる左側の配列の番号を返す(notfound:-1)
	int left_bound(int left, int right,T value){
		return bin_quary(left,right,1,0,size,value,true)-size;
	}
	//指定範囲内で、value以下となる右側に位置を返す(not found:size)
	int right_bound(int left, int right,T value){
		return bin_quary(left,right,1,0,size, value, false)-size;
	}
	//change value 
	void update(int index, T value){
		seg[size+index]=value;
		if (found==false){return ;}
			int ter=index+size;
			while(ter!=1){
				ter/=2;
				seg[ter]=upquary(ter*2);
			} //show();
		}
	//find value
	T find(int l, int r){ //q2
		if(found==false){
			clean(); //show();
		}
		T res = seg[size + l];
		res = findquary(l, r,1,0, size);
		return res;
	}
};
int main(){
	int n,q;
	string s;
	int ans=0;
	cin >>n>>s>>q;
	function<char(char, char)> func = [](char a, char b) { return max(a, b); };
	vector<SegmentTree<char>> data(30, SegmentTree<char>(n, func, 0));
	rep(i, n) { data[s[i] - 'a'].update(i, 1); }
	int id, l, r;
	char c;
	rep(i, q) { 
		cin >>id>>l;
		l--;
		if (id == 1) {
			cin >> c;
			data[s[l] - 'a'].update(l, 0);
			data[c - 'a'].update(l, 1);
			s[l] = c;
		} else {
			cin >> r;
			ans = 0;
			rep(j, 30) { ans += data[j].find(l, r-1); 
			}
		//	clog << s << endl;
			cout << ans << endl;
		}
		    
		
	     }
//	cout<<ans<<endl;
}

Measured memory_bytes: 35692