#!/usr/bin/env python3
import sys, math, itertools, collections, bisect
input = lambda: sys.stdin.buffer.readline().rstrip().decode('utf-8')
inf = float('inf') ;mod = 10**9+7
mans = inf ;ans = 0 ;count = 0 ;pro = 1

class SegmentTree:
  __slots__ = ['ide','n','seg','segfunc']

  def __init__(self,size,func,element):
    self.segfunc = func
    self.ide = element
    # self.size = sizeを超える最小の2冪の数
    self.n = 2 ** (n-1).bit_length()
    # 全てのnodeの数は(2*n-1)個
    # 上にn-1個,最下段にn個
    self.seg = [self.ide] * (2*self.n-1)

  def apply(self,array):
    arraysize = len(array)
    # 配列埋め込み
    for i in range(arraysize):
      self.seg[self.n-1+i] = array[i]
    # 上にあげる
    for i in range(self.n-2,-1,-1):
      self.seg[i] = self.segfunc(self.seg[2*i+1],self.seg[2*i+2])

  def update(self,k,x):
    k += self.n -1
    self.seg[k] = x
    while k:
      k = (k-1)//2
      self.seg[k] = self.segfunc(self.seg[2*k+1],self.seg[2*k+2])

  def query(self,l,r):
    # 半開区間[l,r)
    l += self.n-1; r += self.n-1
    vl = vr = self.ide
    while l < r:
      if l & 1 == 0:
        vl = self.segfunc(vl,self.seg[l])
        l += 1
      if r & 1 == 0:
        vr = self.segfunc(vr,self.seg[r-1])
      l = (l-1)//2; r = (r-1)//2
    return self.segfunc(vl,vr)

    def query2(self, p, q):
        if q <= p:
            return self.ide
        p += self.n - 1
        q += self.n - 2
        res = self.ide
        while q - p > 1:
            if p & 1 == 0:
                res = self.segfunc(res, self.seg[p])
            if q & 1 == 1:
                res = self.segfunc(res, self.seg[q])
                q -= 1
            p = p // 2
            q = (q - 1) // 2 
        if p == q:
            res = self.segfunc(res, self.seg[p])
        else:
            res = self.segfunc(self.segfunc(res, self.seg[p]), self.seg[q])
        return res
    

def segor(a,b):
  return a|b

n = int(input())
st = SegmentTree(n,segor,0)
S = input()
data = [0] * n
for i,si in enumerate(S):
  k = ord(si)-ord("a")
  data[i] = 1 << k
st.apply(data)
Q = int(input())
for _ in range(Q):
  typo,a,b = input().split()
  if typo == "1":
    st.update(int(a)-1,1 << (ord(b)-ord("a")))
  if typo == "2":
    print(bin((st.query2(int(a)-1,int(b))))[2:].count("1"))
  


### FIXED CODE ###

#!/usr/bin/env python3
import sys, math, itertools, collections, bisect
input = lambda: sys.stdin.buffer.readline().rstrip().decode('utf-8')
inf = float('inf') ;mod = 10**9+7
mans = inf ;ans = 0 ;count = 0 ;pro = 1

class Segment_Tree:
    __slots__ = ['ide_ele', 'size', 'num', 'seg', 'segfunc']

    def __init__(self, size, func, element):
        #####単位元######
        self.ide_ele = element
        self.size = size

        #num:n以上の最小の2のべき乗
        self.num = 2 ** (self.size - 1).bit_length()
        self.seg = [self.ide_ele] * 2 * self.num

        #####segfunc######
        self.segfunc = func

    def apply(self, apply_seq):
        #set_val
        for i in range(self.size):
            self.seg[i + self.num - 1] = apply_seq[i]    
        #built
        for i in range(self.num - 2, -1, -1) :
            self.seg[i] = self.segfunc(self.seg[2 * i + 1], self.seg[2 * i + 2]) 
        
    def update(self, k, x):
        k += self.num - 1
        self.seg[k] = x
        while k:
            k = (k-1) // 2
            self.seg[k] = self.segfunc(self.seg[k * 2 + 1],  self.seg[k * 2 + 2])
        
    def query(self, p, q):
        if q <= p:
            return self.ide_ele
        p += self.num - 1
        q += self.num - 2
        res = self.ide_ele
        while q - p > 1:
            if p & 1 == 0:
                res = self.segfunc(res, self.seg[p])
            if q & 1 == 1:
                res = self.segfunc(res, self.seg[q])
                q -= 1
            p = p // 2
            q = (q - 1) // 2 
        if p == q:
            res = self.segfunc(res, self.seg[p])
        else:
            res = self.segfunc(self.segfunc(res, self.seg[p]), self.seg[q])
        return res


def segor(x,y):
  return x | y  

n = int(input())
st = Segment_Tree(n,segor,0)
S = input()
data = [0] * n
for i,si in enumerate(S):
  k = ord(si)-ord("a")
  data[i] = 1 << k
st.apply(data)
Q = int(input())
for _ in range(Q):
  typo,a,b = input().split()
  if typo == "1":
    st.update(int(a)-1,1 << (ord(b)-ord("a")))
  if typo == "2":
    print(bin((st.query(int(a)-1,int(b))))[2:].count("1"))