### BUGGY CODE ###

import sys
from collections import *
import heapq
import math
import bisect
from itertools import permutations,accumulate,combinations,product
from fractions import gcd
import copy
def input():
    return sys.stdin.readline()[:-1]
def ruiseki(lst):
    return [0]+list(accumulate(lst))
mod=pow(10,9)+7

n=int(input())
s=input()
q=int(input())
query=[list(input().split()) for i in range(q)]

al=[chr(ord('a') + i) for i in range(26)]
lst={}
erase={}
insert={}
for i in range(26):
    lst[al[i]]=[]
    erase[al[i]]=[]
    insert[al[i]]=[]

for i in range(n):
    lst[s[i]].append(i)

# print(lst)

for i in range(q):
    if query[i][0]=="1":
        one,j,c=query[i]
        j=int(j)
        if s[j-1]!=c:
            erase[s[j-1]].append(j-1)
            erase[s[j-1]].sort()

            insert[c].append(j-1)
            insert[c].sort()
            s=s[:j-1]+c+s[j:]
    else:
        two,l,r=query[i]
        ans=0
        l=int(l)
        r=int(r)
        for i in range(26):
            tmp=0
            tmp+=bisect.bisect_right(lst[al[i]],r-1)-bisect.bisect_left(lst[al[i]],l-1)
            tmp-=bisect.bisect_right(erase[al[i]],r-1)-bisect.bisect_left(erase[al[i]],l-1)
            tmp+=bisect.bisect_right(insert[al[i]],r-1)-bisect.bisect_left(insert[al[i]],l-1)
            if tmp>0:
                ans+=1
        print(ans)
    # print(s)
    # print(erase)
    # print(insert)

### FIXED CODE ###

import sys
from collections import *
import heapq
import math
import bisect
from itertools import permutations,accumulate,combinations,product
from fractions import gcd
import copy
def input():
    return sys.stdin.readline()[:-1]
def ruiseki(lst):
    return [0]+list(accumulate(lst))
mod=pow(10,9)+7

n=int(input())
s=input()
q=int(input())
qlst=[list(input().split()) for i in range(q)]

lst=[0]*n

for i in range(n):
    lst[i] = pow(2,(ord(s[i])-ord("a")))

# print(lst)
#####segfunc######
def segfunc(x,y):
    return x|y
 
def init(init_val): #渡されたリストでsegを初期化
    #set_val
    for i in range(n):
        seg[i+num-1]=init_val[i]
    #built
    for i in range(num-2,-1,-1) :
        seg[i]=segfunc(seg[2*i+1],seg[2*i+2]) 
    
def update(k,x): #segの要素kをxに変更(セグ木全体の更新)
    k += num-1
    seg[k] = x
    while k:
        k = (k-1)//2
        seg[k] = segfunc(seg[k*2+1],seg[k*2+2])
    
def query(p,q): #区間[p,q)での、segfuncに準じた値を返す
    if q<=p:
        return ide_ele
    p += num-1
    q += num-2
    res=ide_ele
    while q-p>1:
        if p&1 == 0:
            res = segfunc(res,seg[p])
        if q&1 == 1:
            res = segfunc(res,seg[q])
            q -= 1
        p = p//2
        q = (q-1)//2
    if p == q:
        res = segfunc(res,seg[p])
    else:
        res = segfunc(segfunc(res,seg[p]),seg[q])
    return res
 
#####単位元######
"""
最小値のセグ木 → 10**9　(最小値の更新に影響しないため)
　　和のセグ木 → 0　(上の単位元の説明を参照)
　　積のセグ木 → 1　(上の単位元の説明を参照)
　　gcdのセグ木 → 0　(gcdを更新しない値は0)
"""
ide_ele = 0
 
#num:n以上の最小の2のべき乗
num =2**(n-1).bit_length()
seg=[ide_ele]*2*num #単位元の配列(計算結果に影響を及ぼさない配列)を作成
 
init(lst)
# print(seg)
def judge(u):
    res = 0
    for i in range(27):
        if u>>i & 1:
            res += 1
    return res
 
for i in range(q):
    t,x,y = qlst[i]
    if t == "1":
        update(int(x)-1,pow(2,ord(y)-ord("a")))
    else:
        print(judge(query(int(x)-1,int(y))))