package main

import (
	"bufio"
	_ "container/heap"
	"fmt"
	"os"
	_ "sort"
	"strconv"
)

// I/O
type Scanner struct {
	sc *bufio.Scanner
}

func NewScanner() *Scanner {
	sc := bufio.NewScanner(os.Stdin)
	sc.Split(bufio.ScanWords)
	sc.Buffer(make([]byte, 1024), int(1e+9))
	return &Scanner{sc}
}

func (s *Scanner) nextStr() string {
	s.sc.Scan()
	return s.sc.Text()
}

func (s *Scanner) nextInt() int {
	i, e := strconv.Atoi(s.nextStr())
	if e != nil {
		panic(e)
	}
	return i
}

func (s *Scanner) nextFloat() float64 {
	f, e := strconv.ParseFloat(s.nextStr(), 64)
	if e != nil {
		panic(e)
	}
	return f
}

func (s *Scanner) nextRuneSlice() []rune {
	return []rune(s.nextStr())
}

func (s *Scanner) nextIntSlice(n int) []int {
	res := make([]int, n)
	for i := 0; i < n; i++ {
		res[i] = s.nextInt()
	}
	return res
}

func (s *Scanner) nextFloatSlice(n int) []float64 {
	res := make([]float64, n)
	for i := 0; i < n; i++ {
		res[i] = s.nextFloat()
	}
	return res
}

// Arithmetic
func max(nums ...int) int {
	m := nums[0]
	for _, i := range nums {
		if m < i {
			m = i
		}
	}
	return m
}

func min(nums ...int) int {
	m := nums[0]
	for _, i := range nums {
		if m > i {
			m = i
		}
	}
	return m
}

func abs(x int) int {
	if x > 0 {
		return x
	}
	return -x
}

func pow(x, y int) int {
	res := 1
	for i := 0; i < y; i++ {
		res *= x
	}
	return res
}

func ceil(a, b int) int {
	if a%b == 0 {
		return a / b
	} else {
		return a/b + 1
	}
}

func gcd(a, b int) int {
	if b == 0 {
		return a
	}
	return gcd(b, a%b)
}

func lcm(a, b int) int {
	return a / gcd(a, b) * b
}

// Sort
type RuneSlice []rune

func (a RuneSlice) Len() int           { return len(a) }
func (a RuneSlice) Less(i, j int) bool { return a[i] < a[j] }
func (a RuneSlice) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }

// Main
const MOD = int(1e+9) + 7
const INF = 1 << 60

func main() {
	sc := NewScanner()
	wtr := bufio.NewWriter(os.Stdout)
	defer wtr.Flush()
	N, S := sc.nextInt(), sc.nextStr()
	nums := make([]int, N)
	for i, r := range S {
		nums[i] = 1 << uint(r-'a')
	}
	seg := InitSegmentTree(nums, 0, IntMergerOr)
	Q := sc.nextInt()
	for i := 0; i < Q; i++ {
		t := sc.nextInt()
		if t == 1 {
			idx, c := sc.nextInt(), []rune(sc.nextStr())[0]
			seg.UpdateAt(idx-1, 1<<uint(c-'a'))
		} else {
			sum := seg.GetRange(sc.nextInt()-1, sc.nextInt())
			ans := 0
			for j := 0; j < 26; j++ {
				if 1<<uint(j)&sum > 0 {
					ans++
				}
			}
			fmt.Fprintln(wtr, ans)
		}
	}
}

func IntMergerOr(a, b int) int {
	return a | b
}

type Merger func(a, b int) int

type SegmentTree struct {
	offset int
	data   []int
	inf    int
	merge  Merger
}

func InitSegmentTree(a []int, inf int, merge Merger) *SegmentTree {
	n := len(a)
	size := 1
	for size < n {
		size *= 2
	}
	data := make([]int, size*2)

	for j, i := 0, size-1; i < size+n-1; i++ {
		data[i] = a[j]
		j++
	}
	for i := size + n - 1; i < size*2; i++ {
		data[i] = inf
	}
	for i := size - 2; i >= 0; i-- {
		data[i] = merge(data[i*2+1], data[i*2+2])
	}

	return &SegmentTree{
		offset: size,
		data:   data,
		inf:    inf,
		merge:  merge,
	}
}

func (tree *SegmentTree) GetRange(from, to int) int {
	return tree.getRange(from, to, 0, 0, tree.offset)
}

func (tree *SegmentTree) getRange(from, to, index, left, right int) int {
	if to <= left || right <= from {
		return tree.inf
	}
	if from <= left && right <= to {
		return tree.data[index]
	}

	med := (left + right) / 2
	lvalue := tree.getRange(from, to, index*2+1, left, med)
	rvalue := tree.getRange(from, to, index*2+2, med, right)

	return tree.merge(lvalue, rvalue)
}

func (tree *SegmentTree) UpdateAt(index, value int) {
	idx := tree.offset - 1 + index
	tree.data[idx] = value
	for idx >= 1 {
		parent := (idx - 1) / 2
		left := parent*2 + 1
		right := parent*2 + 2

		tree.data[parent] = tree.merge(tree.data[left], tree.data[right])
		idx = parent
	}
}


Measured memory_bytes: 14848