You are given a string S of length N consisting of lowercase English letters.
Process Q queries of the following two types:
 - Type 1: change the i_q-th character of S to c_q. (Do nothing if the i_q-th character is already c_q.)
 - Type 2: answer the number of different characters occurring in the substring of S between the l_q-th and r_q-th characters (inclusive).

-----Constraints-----
 - N, Q, i_q, l_q, and r_q are integers.
 - S is a string consisting of lowercase English letters.
 - c_q is a lowercase English letter.
 - 1 \leq N \leq 500000
 - 1 \leq Q \leq 20000
 - |S| = N
 - 1 \leq i_q \leq N
 - 1 \leq l_q \leq r_q \leq N
 - There is at least one query of type 2 in each testcase.

-----Input-----
Input is given from Standard Input in the following format:
N
S
Q
Query_1
\vdots
Query_Q

Here, Query_i in the 4-th through (Q+3)-th lines is one of the following:
1 i_q c_q

2 l_q r_q

-----Output-----
For each query of type 2, print a line containing the answer.

-----Sample Input-----
7
abcdbbd
6
2 3 6
1 5 z
2 1 1
1 4 a
1 7 d
2 1 7

-----Sample Output-----
3
1
5

In the first query, cdbb contains three kinds of letters: b , c , and d, so we print 3.
In the second query, S is modified to abcdzbd.
In the third query, a contains one kind of letter: a, so we print 1.
In the fourth query, S is modified to abcazbd.
In the fifth query, S does not change and is still abcazbd.
In the sixth query, abcazbd contains five kinds of letters: a, b, c, d, and z, so we print 5.

Difficulty: MEDIUM

Solutions:
import bisect
n = int(input())
s = list(input())
a = {chr(i): [] for i in range(97, 123)}
for (i, c) in enumerate(s):
	bisect.insort(a[c], i + 1)
for i in range(int(input())):
	(p, q, r) = list(map(str, input().split()))
	if p == '1':
		q = int(q)
		b = s[q - 1]
		if b != r:
			a[b].pop(bisect.bisect_left(a[b], q))
			bisect.insort(a[r], q)
			s[q - 1] = r
	else:
		d = 0
		for l in a.values():
			g = bisect.bisect_left(l, int(q))
			if g < len(l) and l[g] <= int(r):
				d += 1
		print(d)


import sys
from bisect import bisect_left, bisect_right, insort
sr = lambda : sys.stdin.readline().rstrip()
ir = lambda : int(sr())
lr = lambda : list(map(int, sr().split()))
N = ir()
S = list('-' + sr())
d = [[] for _ in range(26)]
for i in range(1, N + 1):
	s = S[i]
	o = ord(s) - ord('a')
	insort(d[o], i)
Q = ir()
for _ in range(Q):
	(q, a, b) = sr().split()
	if q == '1':
		a = int(a)
		if S[a] == b:
			continue
		prev = ord(S[a]) - ord('a')
		d[prev].pop(bisect_left(d[prev], a))
		next = ord(b) - ord('a')
		insort(d[next], a)
		S[a] = b
	else:
		a = int(a)
		b = int(b)
		ans = 0
		for alpha in range(26):
			if bisect_right(d[alpha], b) - bisect_left(d[alpha], a) >= 1:
				ans += 1
		print(ans)


class BIT:

	def __init__(self, n):
		self.size = n
		self.bit = [0] * (n + 1)

	def sum(self, i):
		s = 0
		while i > 0:
			s += self.bit[i]
			i -= i & -i
		return s

	def add(self, i, x):
		while i <= self.size:
			self.bit[i] += x
			i += i & -i
n = int(input())
s = input()
q = int(input())
bit = [BIT(n + 1) for i in range(26)]
for i in range(n):
	bit[ord(s[i]) - 97].add(i + 1, 1)
s = list(s)
for _ in range(q):
	(query, a, b) = input().split()
	if query == '1':
		i = int(a)
		c = ord(b) - 97
		bit[c].add(i, 1)
		bit[ord(s[i - 1]) - 97].add(i, -1)
		s[i - 1] = b
	else:
		ans = 0
		for k in range(26):
			if bit[k].sum(int(b)) - bit[k].sum(int(a) - 1) >= 1:
				ans += 1
		print(ans)


n = int(input())
s = list(input())
s = [ord(i) - 97 for i in s]
dic = {}
for i in range(26):
	dic[i] = []
for i in range(n):
	dic[s[i]].append(i)
for i in range(26):
	dic[i].append(float('inf'))
from bisect import bisect_left
q = int(input())
for i in range(q):
	(x, y, z) = input().split()
	if x == '1':
		(y, z) = (int(y) - 1, ord(z) - 97)
		p = bisect_left(dic[s[y]], y)
		dic[s[y]].pop(p)
		dic[z].insert(bisect_left(dic[z], y), y)
		s[y] = z
	else:
		res = 0
		(y, z) = (int(y) - 1, int(z) - 1)
		for i in range(26):
			p = dic[i][bisect_left(dic[i], y)]
			if p <= z:
				res += 1
		print(res)


import bisect
N = int(input())
S = input()
Q = int(input())
alphabet_dic = {}
alphabet_array = []
for (i, s) in enumerate(S):
	alphabet_array.append(s)
	if s in alphabet_dic:
		alphabet_dic[s].append(i)
	else:
		alphabet_dic[s] = [i]
for _ in range(Q):
	(a, b, c) = map(str, input().split())
	if int(a) == 1:
		b = int(b)
		now_str = alphabet_array[b - 1]
		if now_str != c:
			alphabet_array[b - 1] = c
			alphabet_dic[now_str].remove(b - 1)
			if c in alphabet_dic:
				bisect.insort_left(alphabet_dic[c], b - 1)
			else:
				alphabet_dic[c] = [b - 1]
	else:
		ans = 0
		b = int(b)
		c = int(c)
		for index_array in alphabet_dic.values():
			if not len(index_array) or index_array[-1] < b - 1:
				continue
			i = bisect.bisect_left(index_array, b - 1)
			if index_array[i] <= c - 1:
				ans += 1
		print(ans)


def i1():
	return int(input())

def i2():
	return [int(i) for i in input().split()]
import sys
sys.setrecursionlimit(10 ** 6)
n = i1()
s = input()
q = i1()
N = 0
while n:
	n >>= 1
	N += 1
n = 2 ** N
t = [0 for i in range(2 * n - 1)]

def ud(i, x):
	i += n - 1
	t[i] = x
	while i:
		i = (i - 1) // 2
		t[i] = t[i * 2 + 1] | t[i * 2 + 2]

def qr(a, b, k, l, r):
	if r <= a or b <= l:
		return 0
	elif a <= l and r <= b:
		return t[k]
	else:
		return qr(a, b, k * 2 + 1, l, (l + r) // 2) | qr(a, b, k * 2 + 2, (l + r) // 2, r)
for i in range(len(s)):
	ud(i, 1 << ord(s[i]) - ord('a'))
while q:
	[ty, i, c] = [i for i in input().split()]
	ty = int(ty)
	i = int(i)
	if ty == 1:
		ud(i - 1, 1 << ord(c) - ord('a'))
	else:
		c = int(c)
		x = 0
		z = qr(i - 1, c, 0, 0, n)
		while z:
			if z % 2 == 1:
				x += 1
			z >>= 1
		print(x)
	q -= 1


from string import ascii_lowercase
import sys

def input():
	return sys.stdin.readline().strip()

class BIT:

	def __init__(self, n):
		self.n = n
		self.data = [0] * (n + 1)
		self.k_init = 2 ** (self.n - 1).bit_length()

	def sum(self, i):
		s = 0
		while i > 0:
			s += self.data[i]
			i -= i & -i
		return s

	def add(self, i, x):
		while i <= self.n:
			self.data[i] += x
			i += i & -i
n = int(input())
s = input()
q = int(input())
bits = {c: BIT(n) for c in ascii_lowercase}
[bits[c].add(i, 1) for (i, c) in enumerate(s, 1)]
queries = (input().split() for _ in range(q))
for (q_type, *q) in queries:
	if q_type == '1':
		iq = int(q[0])
		cq = q[1]
		for b in bits.values():
			if b.sum(iq) - b.sum(iq - 1) == 1:
				b.add(iq, -1)
				break
		bits[cq].add(iq, 1)
	else:
		(l, r) = map(int, q)
		print(sum([bool(v.sum(r) - v.sum(l - 1) > 0) for v in bits.values()]))


import sys
readline = sys.stdin.readline
from bisect import bisect_left, insort_left

def main():
	n = int(readline())
	s = list(readline().rstrip())
	q = int(readline())
	chk_abc = [[] for i in range(26)]
	for (i, si) in enumerate(s):
		ci = ord(si) - 97
		chk_abc[ci].append(i)
	ans = []
	for _ in range(q):
		(cmd, i, j) = readline().rstrip().split()
		i = int(i) - 1
		if cmd == '1':
			if s[i] == j:
				continue
			c1 = ord(s[i]) - 97
			prev = chk_abc[c1]
			c2 = ord(j) - 97
			prev.pop(bisect_left(prev, i))
			s[i] = j
			insort_left(chk_abc[c2], i)
		else:
			j = int(j) - 1
			num = 0
			for chk in chk_abc:
				le = len(chk)
				k = bisect_left(chk, i, 0, le)
				if k == le:
					continue
				if i <= chk[k] <= j:
					num += 1
			ans.append(num)
	print(*ans, sep='\n')
main()


import bisect
n = int(input().strip())
S = list(input().strip())
L = [[] for _ in range(26)]
for (i, s) in enumerate(S):
	L[ord(s) - ord('a')].append(i)
q = int(input().strip())
for _ in range(q):
	query = input().strip().split()
	if query[0] == '1':
		i = int(query[1])
		i -= 1
		c = query[2]
		if S[i] != c:
			delInd = bisect.bisect_left(L[ord(S[i]) - ord('a')], i)
			del L[ord(S[i]) - ord('a')][delInd]
			bisect.insort(L[ord(c) - ord('a')], i)
			S[i] = c
	else:
		(l, r) = map(int, [query[1], query[2]])
		l -= 1
		r -= 1
		ans = 0
		for j in range(26):
			ind = bisect.bisect_left(L[j], l)
			if ind < len(L[j]) and L[j][ind] <= r:
				ans += 1
		print(ans)


class SegmentTree(object):

	def __init__(self, sequence, function, identify):
		N = len(sequence)
		self.length = (1 << N - 1).bit_length()
		self.function = function
		self.data = [identify] * (self.length << 1)
		self.identify = identify
		for i in range(N):
			self.data[i + self.length - 1] = sequence[i]
		for i in range(self.length - 2, -1, -1):
			self.data[i] = self.function(self.data[(i << 1) + 1], self.data[(i << 1) + 2])

	def update(self, idx, x):
		idx += self.length - 1
		self.data[idx] = x
		while idx:
			idx = idx - 1 >> 1
			self.data[idx] = self.function(self.data[(idx << 1) + 1], self.data[(idx << 1) + 2])

	def query(self, p, q):
		if q <= p:
			return self.identify
		p += self.length - 1
		q += self.length - 2
		res = self.identify
		while q - p > 1:
			if not p & 1:
				res = self.function(res, self.data[p])
			if q & 1:
				res = self.function(res, self.data[q])
				q -= 1
			p >>= 1
			q = q - 1 >> 1
		return self.function(res, self.data[p]) if p == q else self.function(self.function(res, self.data[p]), self.data[q])

def popcount(x):
	x = x - (x >> 1 & 6148914691236517205)
	x = (x & 3689348814741910323) + (x >> 2 & 3689348814741910323)
	x = x + (x >> 4) & 1085102592571150095
	x = x + (x >> 8)
	x = x + (x >> 16)
	x = x + (x >> 32)
	return x & 127
N = int(input())
S = input()
atoi = {chr(ord('a') + d): 1 << d for d in range(26)}
data = [atoi[c] for c in S]
seg_tree = SegmentTree(data, lambda a, b: a | b, 0)
Q = int(input())
for _ in range(Q):
	(q, a, b) = input().split()
	if q == '1':
		idx = int(a) - 1
		seg_tree.update(idx, atoi[b])
	else:
		print(popcount(seg_tree.query(int(a) - 1, int(b))))


from bisect import bisect_left, insort_left
N = int(input())
s = list(input())
Q = int(input())
d = {i: [] for i in range(26)}
for (i, c) in enumerate(s):
	d[ord(c) - ord('a')].append(i)

def convert(d: dict, s: list, q1: int, q2: str):
	if s[q1] == q2:
		return (d, s)
	didx_before = ord(s[q1]) - ord('a')
	didx_after = ord(q2) - ord('a')
	idx = bisect_left(d[didx_before], q1)
	d[didx_before].pop(idx)
	s[q1] = q2
	insort_left(d[didx_after], q1)
	return (d, s)

def calc(d: dict, q1: int, q2: int):
	ans = 0
	for i in range(26):
		idx = bisect_left(d[i], q1)
		if d[i] and q1 <= d[i][-1] and (d[i][idx] < q2 + 1):
			ans += 1
	return ans
for _ in range(Q):
	(q, q1, q2) = input().split()
	q = int(q)
	if q == 1:
		(d, s) = convert(d, s, int(q1) - 1, q2)
	if q == 2:
		print(calc(d, int(q1) - 1, int(q2) - 1))


import sys
input = sys.stdin.readline

class SegTree:

	def __init__(self, size, f=lambda x, y: x | y, e=0):
		self.size = 2 ** (size - 1).bit_length()
		self.e = e
		self.tree = [e] * (self.size * 2)
		self.f = f

	def init_tree(self, l):
		for i in range(len(l)):
			self.tree[i + self.size] = l[i]
		for i in range(self.size - 1, -1, -1):
			self.tree[i] = self.f(self.tree[i * 2], self.tree[i * 2 + 1])

	def update(self, i, v):
		i += self.size
		self.tree[i] = v
		while i > 0:
			i >>= 1
			self.tree[i] = self.f(self.tree[i * 2], self.tree[i * 2 + 1])

	def query(self, l, r):
		l += self.size
		r += self.size
		lval = self.e
		rval = self.e
		while l < r:
			if l & 1:
				lval = self.f(lval, self.tree[l])
				l += 1
			if r & 1:
				r -= 1
				rval = self.f(rval, self.tree[r])
			l >>= 1
			r >>= 1
		return self.f(lval, rval)

def a2i(c):
	return 1 << ord(c) - ord('a')

def main():
	N = int(input())
	S = [a2i(s) for s in input().strip()]
	Q = int(input())
	tree = SegTree(N + 5)
	tree.init_tree(S)
	for _ in range(Q):
		(t, x, y) = input().split()
		if t == '1':
			x = int(x) - 1
			y = 1 << ord(y) - ord('a')
			tree.update(x, y)
		else:
			x = int(x) - 1
			y = int(y)
			tmp = tree.query(x, y)
			ans = 0
			while tmp > 0:
				ans += tmp & 1
				tmp >>= 1
			print(ans)

def __starting_point():
	main()
__starting_point()


import bisect
import sys

def input():
	return sys.stdin.readline().rstrip()
n = int(input())
s = list(input())
q = int(input())
char_idx = [[] for _ in range(26)]
for i in range(n):
	char_idx[ord(s[i]) - ord('a')].append(i)
query = [input().split() for _ in range(q)]
for (t, a, b) in query:
	if t == '1':
		i = int(a) - 1
		if s[i] == b:
			continue
		else:
			idx = bisect.bisect_left(char_idx[ord(s[i]) - ord('a')], i)
			if char_idx[ord(s[i]) - ord('a')][idx] == i:
				del char_idx[ord(s[i]) - ord('a')][idx]
			bisect.insort_left(char_idx[ord(b) - ord('a')], i)
			s[i] = b
	else:
		l = int(a) - 1
		r = int(b) - 1
		ans = 0
		for i in range(26):
			if len(char_idx[i]) == 0:
				continue
			it = bisect.bisect_left(char_idx[i], l)
			if it < len(char_idx[i]) and char_idx[i][it] <= r:
				ans += 1
		print(ans)


import sys
input = sys.stdin.readline

class Bit:

	def __init__(self, n):
		self.size = n
		self.tree = [0] * (n + 1)

	def sum(self, i):
		if i == 0:
			return 0
		s = 0
		while i > 0:
			s += self.tree[i]
			i -= i & -i
		return s

	def add(self, i, x):
		while i <= self.size:
			self.tree[i] += x
			i += i & -i
aas = 'abcdefghijklmnopqrstuvwxyz'
N = int(input().strip())
S = [' '] + list(input().strip())
Q = int(input().strip())
cbt = dict()
for c in aas:
	cbt[c] = Bit(N)
	for (i, a) in enumerate(S):
		if i == 0:
			continue
		if a == c:
			cbt[c].add(i, 1)
for _ in range(Q):
	(t, i, c) = input().split()
	t = int(t)
	if t == 1:
		i = int(i)
		if S[i] != c:
			cbt[S[i]].add(i, -1)
			cbt[c].add(i, 1)
			S[i] = c
	else:
		(l, r) = (int(i), int(c))
		s = 0
		for a in aas:
			bt = cbt[a]
			s += bt.sum(r) - bt.sum(l - 1) > 0
		print(s)


from bisect import bisect_left, insort_left
N = int(input())
S = [c for c in input()]
Q = int(input())
d = {i: [] for i in range(26)}
for (i, c) in enumerate(S):
	d[ord(c) - ord('a')].append(i)
for _ in range(Q):
	q = input().split()
	if int(q[0]) == 1:
		(iq, cq) = (int(q[1]), q[2])
		iq -= 1
		if S[iq] == cq:
			continue
		else:
			idx = bisect_left(d[ord(S[iq]) - ord('a')], iq)
			d[ord(S[iq]) - ord('a')].pop(idx)
			S[iq] = cq
			insort_left(d[ord(cq) - ord('a')], iq)
	else:
		(l, r) = (int(q[1]), int(q[2]))
		l -= 1
		ans = 0
		for i in range(26):
			idx = bisect_left(d[i], l)
			if d[i] and l <= d[i][-1] and (d[i][idx] < r):
				ans += 1
		print(ans)


from operator import or_

class SegmentTree:

	def __init__(self, size, op, e):
		self._op = op
		self._e = e
		self._size = size
		t = 1 << (size - 1).bit_length()
		self._offset = t - 1
		self._data = [e] * (t * 2 - 1)

	def __getitem__(self, key):
		return self._data[self._offset + key]

	def __setitem__(self, key, value):
		op = self._op
		data = self._data
		i = self._offset + key
		data[i] = value
		while i >= 1:
			i = (i - 1) // 2
			data[i] = op(data[i * 2 + 1], data[i * 2 + 2])

	def build(self, iterable):
		op = self._op
		data = self._data
		data[self._offset:self._offset + self._size] = iterable
		for i in range(self._offset - 1, -1, -1):
			data[i] = op(data[i * 2 + 1], data[i * 2 + 2])

	def query(self, start, end):
		op = self._op
		res = self._e
		l = self._offset + start
		r = self._offset + end
		while l < r:
			if l & 1 == 0:
				res = op(res, self._data[l])
			if r & 1 == 0:
				res = op(res, self._data[r - 1])
			l = l // 2
			r = (r - 1) // 2
		return res

def str2bit(c):
	return 1 << ord(c) - ord('a')
N = int(input())
S = input()
st = SegmentTree(N, or_, 0)
st.build((str2bit(x) for x in S))
M = int(input())
for i in range(M):
	(q, a, b) = input().split()
	if q == '1':
		st[int(a) - 1] = str2bit(b)
	elif q == '2':
		print(bin(st.query(int(a) - 1, int(b))).count('1'))


import sys
input = sys.stdin.readline
N = int(input())
S = list(input().rstrip())
ord_a = ord('a')

class Bit:

	def __init__(self, n):
		self.size = n
		self.tree = [0] * (n + 1)

	def sum(self, i):
		s = 0
		while i > 0:
			s += self.tree[i]
			i -= i & -i
		return s

	def add(self, i, x):
		while i <= self.size:
			self.tree[i] += x
			i += i & -i
bits = [Bit(N) for _ in range(26)]
for i in range(N):
	s = S[i]
	bits[ord(s) - ord_a].add(i + 1, 1)
Q = int(input())
for _ in range(Q):
	query = input().rstrip().split()
	if query[0] == '1':
		(i, c) = (int(query[1]), query[2])
		bits[ord(S[i - 1]) - ord_a].add(i, -1)
		S[i - 1] = c
		bits[ord(S[i - 1]) - ord_a].add(i, 1)
	else:
		(l, r) = (int(query[1]), int(query[2]))
		res = 0
		for bit in bits:
			if l != 1:
				res += int(bit.sum(r) - bit.sum(l - 1) > 0)
			else:
				res += int(bit.sum(r) > 0)
		print(res)


import bisect
n = int(input())
s = list(input())
q = int(input())
alphabet = [chr(ord('a') + i) for i in range(26)]
d = {alphabet[i]: [] for i in range(26)}
for (i, a) in enumerate(s):
	d[a].append(i)
ans = []
for i in range(q):
	query = input().split()
	if query[0] == '1':
		(idx, c) = (int(query[1]) - 1, query[2])
		if s[idx] == c:
			continue
		d[s[idx]].remove(idx)
		bisect.insort_left(d[c], idx)
		s[idx] = c
	else:
		(l, r) = (int(query[1]) - 1, int(query[2]) - 1)
		res = 0
		for c in alphabet:
			if bisect.bisect_right(d[c], r) > bisect.bisect_left(d[c], l):
				res += 1
		ans.append(res)
for i in ans:
	print(i)


from bisect import bisect_left, bisect_right, insort_left
n = int(input())
s = list(input())
q = int(input())
d = {}
flag = {}
for i in list('abcdefghijklmnopqrstuvwxyz'):
	d.setdefault(i, []).append(-1)
	flag.setdefault(i, []).append(-1)
for i in range(n):
	d.setdefault(s[i], []).append(i)
for i in range(q):
	(q1, q2, q3) = list(map(str, input().split()))
	if q1 == '1':
		q2 = int(q2) - 1
		if s[q2] != q3:
			insort_left(flag[s[q2]], q2)
			insort_left(d[q3], q2)
			s[q2] = q3
	else:
		ans = 0
		q2 = int(q2) - 1
		q3 = int(q3) - 1
		if q2 == q3:
			print(1)
			continue
		for (string, l) in list(d.items()):
			res = 0
			if d[string] != [-1]:
				left = bisect_left(l, q2)
				right = bisect_right(l, q3)
			else:
				left = 0
				right = 0
			if string in flag:
				left2 = bisect_left(flag[string], q2)
				right2 = bisect_right(flag[string], q3)
			else:
				left2 = 0
				right2 = 0
			if left != right:
				if right - left > right2 - left2:
					res = 1
			ans += res
		print(ans)


from bisect import bisect_left as bl
n = int(input())
s = list(input())
q = int(input())
l = [[] for i in range(26)]
for i in range(n):
	l[ord(s[i]) - ord('a')].append(i)
for i in range(q):
	(x, y, z) = input().split()
	if x == '1':
		y = int(y) - 1
		if s[y] == z:
			continue
		b = ord(s[y]) - ord('a')
		a = ord(z) - ord('a')
		l[b].pop(bl(l[b], y))
		l[a].insert(bl(l[a], y), y)
		s[y] = z
	if x == '2':
		count = 0
		for j in l:
			index = bl(j, int(y) - 1)
			if index < len(j) and j[index] < int(z):
				count += 1
		print(count)


class SegmentTree:

	def __init__(self, n, func, init=float('inf')):
		self.n = 2 ** (n - 1).bit_length()
		self.init = init
		self.data = [init] * (2 * self.n)
		self.func = func

	def set(self, k, v):
		self.data[k + self.n - 1] = v

	def build(self):
		for k in reversed(list(range(self.n - 1))):
			self.data[k] = self.func(self.data[k * 2 + 1], self.data[k * 2 + 2])

	def update(self, k, a):
		k += self.n - 1
		self.data[k] = a
		while k > 0:
			k = (k - 1) // 2
			self.data[k] = self.func(self.data[k * 2 + 1], self.data[k * 2 + 2])

	def query(self, l, r):
		L = l + self.n
		R = r + self.n
		ret = self.init
		while L < R:
			if R & 1:
				R -= 1
				ret = self.func(ret, self.data[R - 1])
			if L & 1:
				ret = self.func(ret, self.data[L - 1])
				L += 1
			L >>= 1
			R >>= 1
		return ret
N = int(input())
S = input()
Q = int(input())
queries = [list(input().split()) for _ in range(Q)]

def a2n(a):
	return ord(a) - ord('a')

def createInp(a):
	return 1 << a2n(a)
Seg = SegmentTree(len(S), lambda x, y: x | y, init=0)
for (i, s) in enumerate(S):
	Seg.set(i, createInp(s))
Seg.build()
for (q, l, r) in queries:
	if q == '1':
		Seg.update(int(l) - 1, createInp(r))
	else:
		print(bin(Seg.query(int(l) - 1, int(r))).count('1'))


class SegmentTree:

	def __init__(self, n, ele=0):
		self.ide_ele = ele
		self.num = 2 ** (n - 1).bit_length()
		self.seg = [self.ide_ele] * 2 * self.num

	def segfunc(self, x, y):
		return x | y

	def init(self, init_val):
		for i in range(len(init_val)):
			self.seg[i + self.num - 1] = init_val[i]
		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
		if self.seg[k] == x:
			return 0
		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
(N, S, Q) = (int(input()), input(), int(input()))
d = {'a': 1, 'b': 2, 'c': 4, 'd': 8, 'e': 16, 'f': 32, 'g': 64, 'h': 128, 'i': 256, 'j': 512, 'k': 1024, 'l': 2048, 'm': 4096, 'n': 8192, 'o': 16384, 'p': 32768, 'q': 65536, 'r': 131072, 's': 262144, 't': 524288, 'u': 1048576, 'v': 2097152, 'w': 4194304, 'x': 8388608, 'y': 16777216, 'z': 33554432}
initial = [d[c] for c in list(S)]
ST = SegmentTree(N)
ST.init(initial)
for _ in range(Q):
	(typ, a, b) = input().split()
	if typ == '1':
		(i, c) = (int(a), d[b])
		ST.update(i - 1, c)
	else:
		(l, r) = (int(a) - 1, int(b))
		x = bin(ST.query(l, r))[2:]
		print(sum(map(int, list(x))))


class BIT:

	def __init__(self, n):
		self.n = n
		self.data = [0] * (n + 1)

	def to_sum(self, i):
		s = 0
		while i > 0:
			s += self.data[i]
			i -= i & -i
		return s

	def add(self, i, x):
		while i <= self.n:
			self.data[i] += x
			i += i & -i

	def get(self, i, j):
		return self.to_sum(j) - self.to_sum(i - 1)
n = int(input())
s = list(input())
q = int(input())
que = []
for i in range(q):
	p = list(input().split())
	que.append(p)
alpha = 'abcdefghijklmnopqrstuvwxyz'
segtree = {alpha[i]: BIT(n) for i in range(26)}
for i in range(n):
	segtree[s[i]].add(i + 1, 1)
for q in que:
	(x, y, z) = (q[0], q[1], q[2])
	if int(x) == 1:
		y = int(y)
		for i in range(26):
			if segtree[alpha[i]].get(y, y) == 1:
				segtree[alpha[i]].add(y, -1)
				break
		segtree[z].add(y, 1)
	else:
		ans = 0
		for i in range(26):
			if segtree[alpha[i]].get(int(y), int(z)) > 0:
				ans += 1
		print(ans)


f = input
(n, s, q) = (int(f()), list(f()), int(f()))
d = {chr(97 + i): [] for i in range(26)}
for i in range(n):
	d[s[i]] += [i]
from bisect import *
for i in range(q):
	(a, b, c) = f().split()
	b = int(b) - 1
	if a == '1':
		if s[b] == c:
			continue
		d[s[b]].pop(bisect(d[s[b]], b) - 1)
		s[b] = c
		insort(d[c], b)
	else:
		t = 0
		for l in d.values():
			m = bisect(l, b - 1)
			if m < len(l) and l[m] < int(c):
				t += 1
		print(t)


from bisect import bisect_left, bisect_right
TO_ACII = 97
N = int(input())
S = ['0'] + list(input())
Q = int(input())
ABC = [[] for i in range(0, 26, 1)]
for i in range(1, N + 1, 1):
	ABC[ord(S[i]) - TO_ACII].append(i)
ans = []
for i in range(0, Q, 1):
	q = list(input().split())
	if q[0] == '1':
		changed = S[int(q[1])]
		ABC[ord(changed) - TO_ACII].pop(bisect_left(ABC[ord(changed) - TO_ACII], int(q[1])))
		ABC[ord(q[2]) - TO_ACII].insert(bisect_left(ABC[ord(q[2]) - TO_ACII], int(q[1])), int(q[1]))
		S[int(q[1])] = q[2]
	else:
		tmpans = 0
		for i in range(0, 26, 1):
			if bisect_right(ABC[i], int(q[1]) - 1) < len(ABC[i]) and int(q[2]) >= ABC[i][bisect_right(ABC[i], int(q[1]) - 1)]:
				tmpans += 1
		ans.append(tmpans)
for i in range(0, len(ans), 1):
	print(ans[i])


import sys
input = sys.stdin.readline

def solve():
	ordA = ord('a')
	N = int(input())
	Ss = input().rstrip()
	Q = int(input())
	querys = [tuple(input().split()) for _ in range(Q)]
	idEle = 0

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

	def makeSegTree(numEle):
		numPow2 = 2 ** (numEle - 1).bit_length()
		data = [idEle] * (2 * numPow2)
		return (data, numPow2)

	def setInit(As):
		for (iST, A) in enumerate(As, numPow2):
			data[iST] = A
		for iST in reversed(list(range(1, numPow2))):
			data[iST] = _binOpe(data[2 * iST], data[2 * iST + 1])

	def _update1(iA, A):
		iST = iA + numPow2
		data[iST] = A

	def update(iA, A):
		_update1(iA, A)
		iST = iA + numPow2
		while iST > 1:
			iST >>= 1
			data[iST] = _binOpe(data[2 * iST], data[2 * iST + 1])

	def getValue(iSt, iEn):
		L = iSt + numPow2
		R = iEn + numPow2
		ans = idEle
		while L < R:
			if L & 1:
				ans = _binOpe(ans, data[L])
				L += 1
			if R & 1:
				R -= 1
				ans = _binOpe(ans, data[R])
			L >>= 1
			R >>= 1
		return ans
	(data, numPow2) = makeSegTree(N)
	As = [1 << ord(S) - ordA for S in Ss]
	setInit(As)
	anss = []
	for (tp, *vs) in querys:
		if tp == '1':
			(i, c) = vs
			i = int(i)
			update(i - 1, 1 << ord(c) - ordA)
		else:
			(L, R) = vs
			(L, R) = (int(L), int(R))
			v = getValue(L - 1, R)
			anss.append(bin(v).count('1'))
	print('\n'.join(map(str, anss)))
solve()


def ctoi(x):
	return ord(x) - ord('a')
n = int(input())
s = list(input())
q = int(input())
bit = [[0] * (n + 1) for _ in range(26)]

def update(pos, a, x):
	while pos <= n:
		bit[a][pos] += x
		pos += pos & -pos

def query(pos):
	ret = [0] * 26
	for i in range(26):
		tmp = 0
		p = pos
		while p > 0:
			tmp += bit[i][p]
			p -= p & -p
		ret[i] = tmp
	return ret
for i in range(n):
	update(i + 1, ctoi(s[i]), 1)
for _ in range(q):
	(flag, a, b) = input().split()
	flag = int(flag)
	a = int(a)
	if flag == 1:
		if s[a - 1] == b:
			continue
		else:
			update(a, ctoi(s[a - 1]), -1)
			update(a, ctoi(b), 1)
			s[a - 1] = b
	else:
		b = int(b)
		c1 = query(b)
		c2 = query(a - 1)
		ans = 0
		for i in range(26):
			if c1[i] - c2[i] > 0:
				ans += 1
		print(ans)


class SegmentTree:

	def __init__(self, n):
		self.siz = 1
		while self.siz < n:
			self.siz *= 2
		self.node = [0] * (2 * self.siz - 1)

	def update(self, i, x):
		i += self.siz - 1
		self.node[i] = x
		while i > 0:
			i = (i - 1) // 2
			self.node[i] = self.node[i * 2 + 1] | self.node[i * 2 + 2]

	def query(self, a, b, k=0, l=0, r=-1):
		if r < 0:
			r = self.siz
		if r <= a or b <= l:
			return 0
		if a <= l and r <= b:
			return self.node[k]
		vl = self.query(a, b, k * 2 + 1, l, (l + r) // 2)
		vr = self.query(a, b, k * 2 + 2, (l + r) // 2, r)
		return vl | vr
n = int(input())
st = SegmentTree(n)
s = list(input())

def f(c):
	return 1 << ord(c) - ord('a')
for i in range(n):
	st.update(i, f(s[i]))
q = int(input())
for _ in range(q):
	(typ, x, y) = input().split()
	if typ == '1':
		(i, c) = (int(x) - 1, y)
		if s[i] == c:
			continue
		st.update(i, f(c))
		s[i] = c
	else:
		(l, r) = (int(x) - 1, int(y))
		print(bin(st.query(l, r)).count('1'))


import bisect
from collections import defaultdict
N = int(input())
S = list(input())
Q = int(input())
dict = defaultdict(list)
for i in range(N):
	dict[S[i]].append(i)
ans = []
for _ in range(Q):
	(a, b, c) = input().split()
	a = int(a)
	if a == 1:
		b = int(b) - 1
		if S[b] == c:
			continue
		else:
			dict[S[b]].remove(b)
			idx = bisect.bisect_left(dict[c], b)
			dict[c].insert(idx, b)
			S[b] = c
	elif a == 2:
		b = int(b) - 1
		c = int(c) - 1
		char_n = 0
		for (key, value) in dict.items():
			if len(value) > 0:
				x1 = bisect.bisect_left(value, b)
				x2 = bisect.bisect_right(value, c)
				if x2 - x1 > 0:
					char_n += 1
		ans.append(char_n)
for i in ans:
	print(i)


import sys

def input():
	return sys.stdin.readline().rstrip()

class SegTree:
	X_unit = 0

	def __init__(self, N, X_f=min):
		self.N = N
		self.X = [self.X_unit] * (N + N)
		self.X_f = X_f

	def build(self, seq):
		for (i, x) in enumerate(seq, self.N):
			self.X[i] = x
		for i in range(self.N - 1, 0, -1):
			self.X[i] = self.X_f(self.X[i << 1], self.X[i << 1 | 1])

	def set_val(self, i, x):
		i += self.N
		self.X[i] = x
		while i > 1:
			i >>= 1
			self.X[i] = self.X_f(self.X[i << 1], self.X[i << 1 | 1])

	def fold(self, L, R):
		L += self.N
		R += self.N
		vL = self.X_unit
		vR = self.X_unit
		while L < R:
			if L & 1:
				vL = self.X_f(vL, self.X[L])
				L += 1
			if R & 1:
				R -= 1
				vR = self.X_f(self.X[R], vR)
			L >>= 1
			R >>= 1
		return self.X_f(vL, vR)

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

def main():
	N = int(input())
	S = input()
	S = list(map(lambda c: 2 ** (ord(c) - ord('a')), list(S)))
	Q = int(input())
	seg = SegTree(N, orr)
	seg.build(S)
	for _ in range(Q):
		(num, x, y) = input().split()
		if num == '1':
			seg.set_val(int(x) - 1, 2 ** (ord(y) - ord('a')))
		else:
			bits = seg.fold(int(x) - 1, int(y))
			print(sum(map(int, list(bin(bits))[2:])))

def __starting_point():
	main()
__starting_point()


n = int(input())
s = list(input())
BITs = [[0] * (n + 1) for _ in range(26)]

def c_idx(c):
	return ord(c) - 97

def query(pos):
	ret = [0] * 26
	for i in range(26):
		tmp = 0
		p = pos
		while p > 0:
			tmp += BITs[i][p]
			p -= p & -p
		ret[i] = tmp
	return ret

def update(pos, a, x):
	while pos <= n:
		BITs[a][pos] += x
		pos += pos & -pos
for i in range(n):
	update(i + 1, c_idx(s[i]), 1)
q = int(input())
for _ in range(q):
	(a, b, c) = input().split()
	b = int(b)
	if a == '1':
		if s[b - 1] == c:
			continue
		update(b, c_idx(s[b - 1]), -1)
		update(b, c_idx(c), 1)
		s[b - 1] = c
	else:
		c = int(c)
		count1 = query(c)
		count2 = query(b - 1)
		ans = 0
		for i in range(26):
			if count1[i] - count2[i] > 0:
				ans += 1
		print(ans)


import math
n = int(input())
s = input()
S = [ord(i) - 97 for i in s]
q = int(input())
HEIGHT = math.ceil(math.log(n) / math.log(2))
SIZE = 1 << HEIGHT

def build_tree():
	tree = [0 for _ in range(SIZE << 1)]
	for (i, letter) in enumerate(s):
		tree[i + SIZE] = 1 << ord(letter) - 97
	for i in range(HEIGHT - 1, -1, -1):
		for x in range(1 << i, 2 << i):
			tree[x] = tree[x << 1] | tree[(x << 1) + 1]
	return tree

def update(x, number):
	tree[x] = number
	while x > 1:
		x >>= 1
		tree[x] = tree[x << 1] | tree[(x << 1) + 1]

def query(l, r):
	total = 0
	while l < r:
		if l & 1:
			total |= tree[l]
			l += 1
		l >>= 1
		if r & 1:
			r -= 1
			total |= tree[r]
		r >>= 1
	return bin(total).count('1')
tree = build_tree()
for i in range(q):
	(a, b, c) = input().split()
	b = int(b) - 1
	if int(a) == 1:
		update(b + SIZE, S[b])
		c = 1 << ord(c) - 97
		S[b] = c
		update(b + SIZE, c)
	else:
		print(query(b + SIZE, int(c) + SIZE))


from bisect import bisect_right
from bisect import bisect_left
n = int(input())
s = list(input())
q = int(input())
ind_list = [[] for _ in range(26)]
for (i, x) in enumerate(s):
	ind_list[ord(x) - 97].append(i)
for _ in range(q):
	(_type, val1, val2) = input().split()
	if _type == '1':
		i = int(val1) - 1
		c = val2
		if s[i] == c:
			continue
		ind_list[ord(s[i]) - 97].remove(i)
		p = bisect_right(ind_list[ord(c) - 97], i)
		ind_list[ord(c) - 97].insert(p, i)
		s[i] = c
	elif _type == '2':
		l = int(val1) - 1
		r = int(val2) - 1
		ans = 0
		for i in range(26):
			if bisect_right(ind_list[i], r) - bisect_left(ind_list[i], l) > 0:
				ans += 1
		print(ans)
	else:
		print('Exception caught!')
		exit()


class SegmentTree:

	def __init__(self, iterable, func, e):
		self.func = func
		self.e = e
		ls = list(iterable)
		self.n = 1 << len(ls).bit_length()
		ls.extend([self.e] * (self.n - len(ls)))
		self.data = [self.e] * self.n + ls
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.func(self.data[2 * i], self.data[2 * i + 1])

	def replace(self, index, value):
		index += self.n
		self.data[index] = value
		index //= 2
		while index > 0:
			self.data[index] = self.func(self.data[2 * index], self.data[2 * index + 1])
			index //= 2

	def folded(self, l, r):
		left_folded = self.e
		right_folded = self.e
		l += self.n
		r += self.n
		while l < r:
			if l % 2:
				left_folded = self.func(left_folded, self.data[l])
				l += 1
			if r % 2:
				r -= 1
				right_folded = self.func(self.data[r], right_folded)
			l //= 2
			r //= 2
		return self.func(left_folded, right_folded)
from operator import or_
N = int(input())
S = input()
ls = [1 << ord(c) - ord('a') for c in S]
segtree = SegmentTree(ls, or_, 0)
Q = int(input())
for _ in range(Q):
	s = input()
	if s[0] == '1':
		(i, c) = s[2:].split()
		segtree.replace(int(i) - 1, 1 << ord(c) - ord('a'))
	else:
		(l, r) = list(map(int, s[2:].split()))
		value = segtree.folded(l - 1, r)
		print(format(value, 'b').count('1'))


import bisect
import sys
input = lambda : sys.stdin.readline().rstrip()
n = int(input())
s = list(input())
q = []
qq = int(input())
for i in range(qq):
	q.append(list(input().split()))
x = [[] for i in range(26)]
for (i, j) in enumerate(s):
	x[ord(j) - 97].append(i)
for i in range(26):
	x[i].append(5 * 10 ** 5)
for (i, j, k) in q:
	if int(i) == 1:
		if s[int(j) - 1] != k:
			v = s[int(j) - 1]
			s[int(j) - 1] = k
			index = bisect.bisect_right(x[ord(v) - 97], int(j) - 1) - 1
			x[ord(v) - 97].pop(index)
			bisect.insort_right(x[ord(k) - 97], int(j) - 1)
	else:
		cnt = 0
		j = int(j) - 1
		k = int(k) - 1
		for l in range(26):
			index = bisect.bisect_left(x[l], j)
			if x[l][index] <= k:
				cnt += 1
		print(cnt)


from collections import defaultdict
from bisect import bisect_left, bisect_right, insort_left, insort_right
import sys
input = sys.stdin.readline

def main():
	N = int(input())
	S = list(input())
	q = int(input())
	Q = [input() for _ in range(q)]
	dd = defaultdict(list)
	for i in range(ord('a'), ord('z') + 1):
		dd[chr(i)] = []
	for (i, st) in enumerate(S):
		dd[st].append(i)
	ans = []
	for q in Q:
		(t, a, b) = q.split()
		a = int(a) - 1
		if int(t) == 1:
			if S[a] == b:
				continue
			id = bisect_left(dd[S[a]], a)
			dd[S[a]].pop(id)
			insort_left(dd[b], a)
			S[a] = b
		else:
			b = int(b) - 1
			cnt = 0
			for l in dd.values():
				if l and a <= l[-1] and (l[bisect_left(l, a)] <= b):
					cnt += 1
			ans.append(cnt)
	print(*ans, sep='\n')

def __starting_point():
	main()
__starting_point()


class SEGTree:

	def __init__(self, n):
		self.Unit = 0
		i = 1
		while i < n:
			i *= 2
		self.SEG = [self.Unit] * (2 * i - 1)
		self.d = i

	def update(self, i, x):
		i += self.d - 1
		self.SEG[i] = 1 << x
		while i > 0:
			i = (i - 1) // 2
			self.SEG[i] = self.SEG[i * 2 + 1] | self.SEG[i * 2 + 2]

	def find(self, a, b, k, l, r):
		if r <= a or b <= l:
			return self.Unit
		if a <= l and r <= b:
			return self.SEG[k]
		else:
			c1 = self.find(a, b, 2 * k + 1, l, (l + r) // 2)
			c2 = self.find(a, b, 2 * k + 2, (l + r) // 2, r)
			return c1 | c2

	def get(self, a, b):
		return self.find(a, b, 0, 0, self.d)

def bitcnt(x):
	res = 0
	while x > 0:
		if x & 1:
			res += 1
		x //= 2
	return res
n = int(input())
s = input()
q = int(input())
seg = SEGTree(n)
for i in range(n):
	seg.update(i, ord(s[i]) - 97)
for i in range(q):
	(q, x, y) = input().split()
	if q == '1':
		seg.update(int(x) - 1, ord(y) - 97)
	else:
		(x, y) = (int(x) - 1, int(y))
		bit = seg.get(x, y)
		print(bitcnt(bit))


import sys
input = sys.stdin.readline
N = int(input())
S = input().rstrip()
Q = int(input())
qs = [input().split() for i in range(Q)]

def ctoi(c):
	return ord(c) - ord('a')
bit = [[0] * (N + 2) for _ in range(26)]

def bit_add(x, w, ci):
	while x <= N + 1:
		bit[ci][x] += w
		x += x & -x

def bit_sum(x, ci):
	ret = 0
	while x > 0:
		ret += bit[ci][x]
		x -= x & -x
	return ret
for (i, c) in enumerate(S):
	bit_add(i + 1, 1, ctoi(c))
s = list(S)
ans = []
for (a, b, c) in qs:
	if a == '1':
		x = int(b)
		bit_add(x, 1, ctoi(c))
		bit_add(x, -1, ctoi(s[x - 1]))
		s[x - 1] = c
	else:
		tmp = 0
		for i in range(26):
			if bit_sum(int(c), i) - bit_sum(int(b) - 1, i) > 0:
				tmp += 1
		ans.append(tmp)
print(*ans, sep='\n')


import sys
from bisect import bisect_left, bisect_right, insort

def main():
	n = int(input())
	s = list(str(input()))
	p = [[] for _ in range(26)]
	for (i, S) in enumerate(s):
		p[ord(S) - ord('a')].append(i)
	q = int(input())
	for i in range(q):
		(a, b, c) = map(str, input().split())
		if a == '1':
			b = int(b) - 1
			if s[b] == c:
				continue
			else:
				insl = bisect_left(p[ord(s[b]) - ord('a')], b)
				p[ord(s[b]) - ord('a')].pop(insl)
				insort(p[ord(c) - ord('a')], b)
				s[b] = c
		else:
			(b, c) = (int(b) - 1, int(c) - 1)
			cnt = 0
			for i in range(26):
				insl = bisect_left(p[i], b)
				if insl >= len(p[i]):
					continue
				elif p[i][insl] <= c:
					cnt += 1
			print(cnt)
main()


n = int(input())
from bisect import bisect_left, bisect_right
s = list(input())
q = int(input())
D = {chr(ord('a') + i): [] for i in range(26)}
for (i, j) in enumerate(s):
	D[j].append(i)
ans = 0
for i in range(q):
	x = list(input().split())
	if x[0] == '1':
		l = int(x[1])
		l -= 1
		r = x[-1]
		if r == s[l]:
			continue
		rr = bisect_left(D[r], l)
		D[s[l]].remove(l)
		D[r].insert(rr, l)
		s[l] = r
	else:
		l = int(x[1])
		r = int(x[2])
		l -= 1
		r -= 1
		ans = 0
		for i in range(26):
			W = chr(ord('a') + i)
			ll = bisect_left(D[W], l)
			rr = bisect_right(D[W], r)
			if rr - ll > 0:
				ans += 1
		print(ans)


n = int(input()) + 1
w = input()
data = [0] * n * 2

def update(i, x):
	i += n
	data[i] = x
	i //= 2
	while i:
		data[i] = data[i * 2] | data[i * 2 + 1]
		i //= 2

def query(l, r):
	l += n
	r += n
	s = 0
	while l < r:
		if l & 1 == 1:
			s |= data[l]
			l += 1
		if r & 1 == 1:
			r -= 1
			s |= data[r]
		l //= 2
		r //= 2
	return bin(s).count('1')

def word_num(a):
	return 1 << ord(a) - 97
for i in range(n - 1):
	data[i + n] = word_num(w[i])
for i in range(n - 1, 0, -1):
	data[i] = data[i * 2] | data[i * 2 + 1]
ans = []
q = int(input())
for i in range(q):
	(a, s, t) = input().split()
	if a == '1':
		s = int(s)
		update(int(s) - 1, word_num(t))
	if a == '2':
		s = int(s)
		t = int(t)
		ans.append(query(int(s) - 1, int(t)))
for i in range(len(ans)):
	print(ans[i])


def main():
	import sys
	input = sys.stdin.buffer.readline
	n = int(input()) + 1
	data = [[0] * n * 2 for _ in range(26)]

	def update(i, x):
		i += n
		for d in data:
			j = i
			if d[j]:
				d[j] = 0
				j //= 2
				while j:
					d[j] = d[j + j] | d[j - ~j]
					j //= 2
				break
		d = data[x]
		d[i] = 1
		i //= 2
		while i:
			d[i] = d[i + i] | d[i - ~i]
			i //= 2

	def query(l, r):
		l += n
		r += n
		s = [0] * 26
		while l < r:
			if l & 1:
				for (i, d) in enumerate(data):
					s[i] |= d[l]
				l += 1
			if r & 1:
				r -= 1
				for (i, d) in enumerate(data):
					s[i] |= d[r]
			l //= 2
			r //= 2
		return sum(s)
	for (i, c) in enumerate(input()[:-1]):
		update(i, c - 97)
	s = []
	for _ in range(int(input())):
		(q, a, b) = input().split()
		if q[0] > 49:
			s += (query(int(a) - 1, int(b)),)
		else:
			update(int(a) - 1, b[0] - 97)
	print('\n'.join(map(str, s)))
main()


import sys
input = sys.stdin.readline

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

def init(init_val):
	for i in range(n):
		seg[i + num - 1] = init_val[i]
	for i in range(num - 2, -1, -1):
		seg[i] = segfunc(seg[2 * i + 1], seg[2 * i + 2])

def update(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):
	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
n = int(input())
s = input()
q = int(input())
li = []
for i in range(n):
	li.append(1 << ord(s[i]) - ord('a'))
ide_ele = 0
num = 2 ** (n - 1).bit_length()
seg = [ide_ele] * 2 * num
init(li)
for _ in range(q):
	q1 = list(input().split())
	if q1[0] == '1':
		update(int(q1[1]) - 1, 1 << ord(q1[2]) - ord('a'))
	else:
		(l, r) = (int(q1[1]), int(q1[2]))
		print(bin(query(l - 1, r)).count('1'))


class BIT:

	def __init__(self, N):
		self.size = N
		self.tree = [0] * (N + 1)

	def sum(self, i):
		s = 0
		while i > 0:
			s += self.tree[i]
			i -= i & -i
		return s

	def add(self, i, x):
		while i <= self.size:
			self.tree[i] += x
			i += i & -i
sc = iter(open(0).read().split())
ni = lambda : int(next(sc))
ns = lambda : next(sc)
(N, S, Q) = (ni(), list(ns()), ni())
B = [BIT(N) for _ in range(26)]
for (i, s) in enumerate(S, 1):
	B[ord(s) - ord('a')].add(i, 1)
A = []
for _ in range(Q):
	if ni() == 1:
		(i, c) = (ni(), ns())
		B[ord(S[i - 1]) - ord('a')].add(i, -1)
		S[i - 1] = c
		B[ord(c) - ord('a')].add(i, 1)
	else:
		(l, r) = (ni(), ni())
		A.append(sum((b.sum(l - 1) < b.sum(r) for b in B)))
print('\n'.join(map(str, A)))


import sys

def input():
	return sys.stdin.readline().rstrip()
from bisect import bisect_left, bisect

def main():
	n = int(input())
	S = list(input())
	q = int(input())
	set_s = {chr(ord('a') + i): [] for i in range(26)}
	for (i, s) in enumerate(S):
		set_s[s].append(i)
	for _ in range(q):
		query = input().split()
		if query[0] == '1':
			(i, c) = (int(query[1]) - 1, query[2])
			if S[i] == c:
				continue
			set_s[S[i]].remove(i)
			set_s[c].insert(bisect_left(set_s[c], i), i)
			S[i] = c
		else:
			(l, r) = (int(query[1]) - 1, int(query[2]) - 1)
			ans = 0
			for i in range(26):
				ss = chr(ord('a') + i)
				if bisect(set_s[ss], r) > bisect_left(set_s[ss], l):
					ans += 1
			print(ans)
main()


from string import ascii_lowercase
import sys

def input():
	return sys.stdin.readline().strip()

def sum_b(data, i):
	s = 0
	while i > 0:
		s += data[i]
		i -= i & -i
	return s

def add_b(data, i, x):
	while i <= n:
		data[i] += x
		i += i & -i
n = int(input())
s = input()
q = int(input())
bits = {c: [0] * (n + 1) for c in ascii_lowercase}
[add_b(bits[c], i, 1) for (i, c) in enumerate(s, 1)]
for (q_type, *q) in (input().split() for _ in range(q)):
	if q_type == '1':
		iq = int(q[0])
		cq = q[1]
		for b in bits.values():
			if sum_b(b, iq) - sum_b(b, iq - 1) == 1:
				add_b(b, iq, -1)
				break
		add_b(bits[cq], iq, 1)
	else:
		(l, r) = map(int, q)
		print(sum([bool(sum_b(b, r) - sum_b(b, l - 1) > 0) for b in bits.values()]))


def RSQ_add(i, x, y):
	while True:
		if i > n:
			break
		BIT[y][i] += x
		i += i & -i

def RSQ_getsum(i, x):
	s = 0
	while True:
		if i <= 0:
			break
		s += BIT[x][i]
		i -= i & -i
	return s
n = int(input())
s = list(input())
q = int(input())
BIT = [[0] * (n + 1) for _ in range(26)]
for i in range(n):
	y = ord(s[i]) - 97
	RSQ_add(i + 1, 1, y)
for _ in range(q):
	(com, a, b) = map(str, input().split())
	(com, a) = (int(com), int(a))
	if com == 1:
		RSQ_add(a, -1, ord(s[a - 1]) - 97)
		RSQ_add(a, 1, ord(b) - 97)
		s[a - 1] = b
	else:
		b = int(b)
		ans = 0
		for i in range(26):
			if RSQ_getsum(b, i) - RSQ_getsum(a - 1, i) >= 1:
				ans += 1
		print(ans)


def BIT_query(BIT, idx):
	res_sum = 0
	while idx > 0:
		res_sum += BIT[idx]
		idx -= idx & -idx
	return res_sum

def BIT_update(BIT, idx, x):
	while idx <= n:
		BIT[idx] += x
		idx += idx & -idx
	return
alps = 'abcdefghijklmnopqrstuvwxyz'
n = int(input())
s = list(input())
char_hd_d = {}
for alp in alps:
	char_hd_d[alp] = [0] * (n + 1)
for (i, si) in enumerate(s):
	BIT_update(char_hd_d[si], i + 1, 1)
q = int(input())
ansl = []
for _ in range(q):
	(command, a, b) = input().split()
	if command == '1':
		i = int(a)
		c = b
		i_char = s[i - 1]
		BIT_update(char_hd_d[i_char], i, -1)
		BIT_update(char_hd_d[c], i, 1)
		s[i - 1] = c
	else:
		(l, r) = (int(a), int(b))
		cnt = 0
		for alp in alps:
			if BIT_query(char_hd_d[alp], r) - BIT_query(char_hd_d[alp], l - 1) > 0:
				cnt += 1
		ansl.append(cnt)
for a in ansl:
	print(a)


class SegmentTree:

	def __init__(self, a, identity=0):
		self.a = a
		self.n = len(a)
		self.identity = identity
		self.depth = (self.n - 1).bit_length()
		self.segment = (1 << self.depth) - 1
		self.tree = [identity] * (self.segment * 2 + 1)
		self.tree[self.segment:self.n + self.segment] = a
		for i in range(self.segment - 1, -1, -1):
			self.tree[i] = self.f(self.tree[2 * i + 1], self.tree[2 * i + 2])

	def update(self, i: int, x: int):
		i += self.segment
		self.tree[i] = x
		while i:
			i = (i - 1) // 2
			self.tree[i] = self.f(self.tree[2 * i + 1], self.tree[2 * i + 2])

	def query(self, l: int, r: int) -> int:
		if l > r:
			return self.identity
		l += self.segment
		r += self.segment
		res = self.identity
		while l <= r:
			if not l & 1:
				res = self.f(self.tree[l], res)
			if r & 1:
				res = self.f(res, self.tree[r])
			l = l // 2
			r = (r - 2) // 2
		return res

	def f(self, x: int, y: int) -> int:
		return x | y
n = int(input())
s = input()
q = int(input())
a = ord('a')
segment_tree = SegmentTree([1 << ord(c) - a for c in s])
for _ in range(q):
	query = input().split()
	if query[0] == '1':
		i = int(query[1]) - 1
		c = query[2]
		segment_tree.update(i, 1 << ord(c) - a)
	else:
		l = int(query[1]) - 1
		r = int(query[2]) - 1
		bit = segment_tree.query(l, r)
		print(format(bit, 'b').count('1'))


import bisect
N = int(input())
S = list(str(input()))

def ci(x):
	return 'abcdefghijklmnopqrstuvwxyz'.find(x)
d = [[] for _ in range(26)]
for (i, s) in enumerate(S):
	d[ci(s)].append(i)
for i in range(int(input())):
	(t, x, y) = input().split()
	if t == '1':
		x = int(x) - 1
		if S[x] != y:
			l = bisect.bisect_left(d[ci(S[x])], x)
			d[ci(S[x])].pop(l)
			bisect.insort(d[ci(y)], x)
			S[x] = y
	else:
		(x, y) = (int(x) - 1, int(y) - 1)
		c = 0
		for j in range(26):
			l = bisect.bisect_left(d[j], x)
			if l < len(d[j]) and d[j][l] <= y:
				c += 1
		print(c)


import bisect

def main():
	n = int(input())
	s = bytearray(input().encode())
	q = int(input())
	alpha = [ord('a') + i for i in range(26)]
	alpha_map = {c: [] for c in alpha}
	for (i, c) in enumerate(s):
		bisect.insort(alpha_map[c], i + 1)
	for _ in range(q):
		(t, a, b) = [p for p in input().split()]
		t = int(t)
		a = int(a)
		if t == 1:
			char = s[a - 1]
			b = ord(b)
			if char == b:
				continue
			src_lst = alpha_map[char]
			dst_lst = alpha_map[b]
			idx = bisect.bisect_left(src_lst, a)
			if idx < len(src_lst):
				src_lst.pop(idx)
			bisect.insort(dst_lst, a)
			s[a - 1] = b
		else:
			b = int(b)
			cnt = 0
			for (_, lst) in alpha_map.items():
				idx = bisect.bisect_left(lst, a)
				if idx < len(lst) and lst[idx] <= b:
					cnt += 1
			print(cnt)
main()


import sys
input = sys.stdin.readline
n = int(input())
S = input()
nagasa = len(list(S))
num = 2 ** (nagasa - 1).bit_length()
SEG = [0] * 2 * num

def word_num(a):
	return 1 << ord(a) - 96

def init(S):
	for i in range(n):
		SEG[i + num - 1] = word_num(S[i])
	for i in range(num - 2, -1, -1):
		SEG[i] = SEG[2 * i + 1] | SEG[2 * i + 2]

def update(k, x):
	k += num - 1
	SEG[k] = word_num(x)
	while k:
		k -= 1
		k //= 2
		SEG[k] = SEG[k * 2 + 1] | SEG[k * 2 + 2]

def query(p, q):
	if q <= p:
		return 0
	p += num - 1
	q += num - 2
	ans = 0
	while q - p > 1:
		if p & 1 == 0:
			ans |= SEG[p]
		if q & 1 == 1:
			ans |= SEG[q]
			q -= 1
		p //= 2
		q -= 1
		q //= 2
	if p == q:
		ans |= SEG[p]
	else:
		ans |= SEG[p]
		ans |= SEG[q]
	return ans
init(S)
q = int(input())
for i in range(q):
	(a, s, t) = input().split()
	if a == '1':
		s = int(s)
		update(s - 1, t)
	if a == '2':
		s = int(s)
		t = int(t)
		print(bin(query(s - 1, t)).count('1'))


N = int(input())
S = [ord(i) - 97 for i in input()]
Q = int(input())

class BinaryIndexedTree:

	def __init__(self, N):
		self.size = N
		self.tree = [0] * (N + 1)

	def sum(self, i):
		s = 0
		while i > 0:
			s += self.tree[i]
			i -= i & -i
		return s

	def add(self, i, x):
		while i <= self.size:
			self.tree[i] += x
			i += i & -i
alph = [BinaryIndexedTree(N + 10) for _ in range(26)]
for i in range(N):
	alph[S[i]].add(i + 1, 1)
for _ in range(Q):
	(type, x, y) = input().split()
	if type == '1':
		x = int(x)
		s = S[x - 1]
		alph[s].add(x, -1)
		alph[ord(y) - 97].add(x, 1)
		S[x - 1] = ord(y) - 97
	else:
		(x, y) = (int(x), int(y))
		ret = 0
		for i in range(26):
			if alph[i].sum(y) - alph[i].sum(x - 1) > 0:
				ret += 1
		print(ret)


n = int(input()) + 1
data = [0] * n * 2

def update(i, x):
	i += n
	data[i] = x
	i //= 2
	while i:
		data[i] = data[i * 2] | data[i * 2 + 1]
		i //= 2

def query(l, r):
	l += n
	r += n
	s = 0
	while l < r:
		if l & 1:
			s |= data[l]
			l += 1
		if r & 1:
			r -= 1
			s |= data[r]
		l //= 2
		r //= 2
	return sum(map(int, bin(s)[2:]))
s = input()
for (i, c) in enumerate(s, n):
	data[i] = 1 << ord(c) - 97
for i in range(n - 1, 0, -1):
	data[i] = data[2 * i] | data[2 * i + 1]
for _ in range(int(input())):
	(q, a, b) = input().split()
	if q == '2':
		print(query(int(a) - 1, int(b)))
	else:
		update(int(a) - 1, 1 << ord(b) - 97)


import bisect
N = int(input())
S = list(input())
Q = int(input())
alphabet = 'abcdefghijklmnopqrstuvwxyz'
bag = {l: [] for l in alphabet}
for i in range(N):
	bag[S[i]].append(i + 1)
for i in range(Q):
	(Type, a, b) = input().split()
	if Type == '1':
		a = int(a)
		if S[a - 1] != b:
			bag[S[a - 1]].remove(a)
			S[a - 1] = b
			bisect.insort(bag[b], a)
	else:
		cnt = 0
		(a, b) = (int(a), int(b))
		for l in alphabet:
			bl = len(bag[l])
			if bl > 0:
				left = bisect.bisect_left(bag[l], a)
				if left != bl and bag[l][left] <= b:
					cnt += 1
		print(cnt)


n = int(input())
s = list(input())
q = int(input())

def ctoi(c):
	return ord(c) - 97

class Bit:

	def __init__(self, n):
		self.size = n
		self.tree = [[0] * (n + 1) for _ in range(26)]

	def query(self, a, i):
		r = 0
		while i > 0:
			r += self.tree[a][i]
			i -= i & -i
		return r

	def update(self, i, a, x):
		while i <= n:
			self.tree[a][i] += x
			i += i & -i
bi = Bit(n)
for i in range(n):
	bi.update(i + 1, ctoi(s[i]), 1)
for _ in range(q):
	(a, b, c) = input().split()
	(a, b) = (int(a), int(b))
	if a == 1 and s[b - 1] != c:
		bi.update(b, ctoi(s[b - 1]), -1)
		bi.update(b, ctoi(c), 1)
		s[b - 1] = c
	elif a == 2:
		c = int(c)
		right = [bi.query(i, c) for i in range(26)]
		left = [bi.query(i, b - 1) for i in range(26)]
		ans = 0
		for (r, l) in zip(right, left):
			if r - l > 0:
				ans += 1
		print(ans)


n = int(input())
s = input()
table = {x: 2 ** i for (i, x) in enumerate(map(chr, range(97, 123)))}
SEG_LEN = n
SEG = [0] * (SEG_LEN * 2)

def update(i, x):
	i += SEG_LEN
	SEG[i] = table[x]
	while i > 0:
		i //= 2
		SEG[i] = SEG[i * 2] | SEG[i * 2 + 1]

def find(left, right):
	left += SEG_LEN
	right += SEG_LEN
	ans = 0
	while left < right:
		if left % 2 == 1:
			ans = SEG[left] | ans
			left += 1
		left //= 2
		if right % 2 == 1:
			ans = SEG[right - 1] | ans
			right -= 1
		right //= 2
	return format(ans, 'b').count('1')
for (i, c) in enumerate(s):
	update(i, c)
q = int(input())
for _ in range(q):
	(com, *query) = input().split()
	if com == '1':
		(idx, x) = query
		update(int(idx) - 1, x)
	else:
		(L, R) = map(int, query)
		print(find(L - 1, R))


f = input
from bisect import bisect_left as g, insort as h
f()
(s, i) = (list(f()), 0)
from collections import *
d = defaultdict(list)
for c in s:
	d[c] += [i]
	i += 1
for _ in range(int(f())):
	(a, b, c) = f().split()
	b = int(b) - 1
	if a > '1':
		print(sum((1 for l in d.values() if g(l, b) < len(l) and l[g(l, b)] < int(c))))
	elif s[b] != c:
		l = d[s[b]]
		l.pop(g(l, b))
		s[b] = c
		h(d[c], b)


import bisect
n = int(input())
s = input()
q = int(input())
idxs = [[] for i in range(26)]
sl = [s[i] for i in range(n)]
for i in range(n):
	idxs[ord(s[i]) - ord('a')].append(i + 1)
qs = []
for i in range(q):
	qs.append(input())
for qi in qs:
	(op, x, y) = qi.split()
	if op == '1':
		j = int(x)
		c = y
		oc = sl[j - 1]
		if oc != c:
			sl[j - 1] = c
			idx = bisect.bisect_left(idxs[ord(oc) - ord('a')], j)
			del idxs[ord(oc) - ord('a')][idx]
			idx = bisect.bisect_left(idxs[ord(c) - ord('a')], j)
			idxs[ord(c) - ord('a')].insert(idx, j)
	elif op == '2':
		l = int(x)
		r = int(y)
		c = 0
		for i in range(26):
			il = bisect.bisect_left(idxs[i], l)
			ir = bisect.bisect_right(idxs[i], r)
			if il < ir:
				c += 1
		print(c)


import bisect
n = int(input())
s = list(input())
q = int(input())
alpha_map = {chr(i): [] for i in range(97, 123)}
for (i, c) in enumerate(s):
	bisect.insort(alpha_map[c], i + 1)
for _ in range(q):
	(x, y, z) = map(str, input().split())
	if int(x) == 1:
		y = int(y)
		bef = s[y - 1]
		if bef == z:
			continue
		alpha_map[bef].pop(bisect.bisect_left(alpha_map[bef], y))
		bisect.insort(alpha_map[z], y)
		s[y - 1] = z
	else:
		count = 0
		for (i, j) in alpha_map.items():
			idx = bisect.bisect_left(j, int(y))
			if idx < len(j) and j[idx] <= int(z):
				count += 1
		print(count)


class Bit:

	def __init__(self, n):
		self.size = n
		self.tree = [0] * (n + 1)

	def add(self, i, x):
		while i <= self.size:
			self.tree[i] += x
			i += i & -i

	def sum(self, i):
		s = 0
		while i > 0:
			s += self.tree[i]
			i -= i & -i
		return s

def enc(a):
	return ord(a) - ord('a')
N = int(input())
S = input()
bits = [Bit(N) for i in range(26)]
for (i, s) in enumerate(S):
	bits[enc(s)].add(i + 1, 1)
for _ in range(int(input())):
	(t, l, r) = input().split(' ')
	if t == '1':
		i = int(l)
		before = -1
		for before in range(26):
			if bits[before].sum(i) - bits[before].sum(i - 1) == 1:
				break
		after = enc(r)
		bits[before].add(i, -1)
		bits[after].add(i, 1)
	else:
		(l, r) = map(int, [l, r])
		ans = 0
		for c in range(26):
			if bits[c].sum(r) - bits[c].sum(l - 1) > 0:
				ans += 1
		print(ans)


import bisect
N = input()
S = list(input())
alphabet = [[] for _ in range(26)]
for (i, s) in enumerate(S):
	alphabet[ord(s) - ord('a')].append(i)
Q = int(input())
for _ in range(Q):
	(Type, A, B) = input().split()
	if Type == '1':
		A = int(A)
		s = S[A - 1]
		if s == B:
			continue
		o = ord(s) - ord('a')
		alphabet[o].pop(bisect.bisect_left(alphabet[o], A - 1))
		index = bisect.bisect(alphabet[ord(B) - ord('a')], A - 1)
		alphabet[ord(B) - ord('a')].insert(index, A - 1)
		S[A - 1] = B
	else:
		A = int(A)
		B = int(B)
		ans = 0
		for i in range(26):
			indexL = bisect.bisect_left(alphabet[i], A - 1)
			if indexL == len(alphabet[i]):
				continue
			ans += alphabet[i][indexL] <= B - 1
		print(ans)


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

def init(init_val):
	for i in range(n):
		seg[i + num - 1] = init_val[i]
	for i in range(num - 2, -1, -1):
		seg[i] = segfunc(seg[2 * i + 1], seg[2 * i + 2])

def update(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):
	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
ide_ele = set([])
n = int(input())
S = [set([s]) for s in input()]
num = 2 ** (n - 1).bit_length()
seg = [ide_ele] * 2 * num
init(S)
q = int(input())
for _ in range(q):
	(a, b, c) = input().split()
	if a == '1':
		b = int(b) - 1
		update(b, set([c]))
	elif a == '2':
		b = int(b) - 1
		c = int(c)
		print(len(query(b, c)))


n = int(input())
s = input()
q = int(input())
queris = []
for _ in range(q):
	(t, a, b) = input().split()
	queris.append((t, a, b))
size = 1
while size < n:
	size *= 2
seg = [0] * (2 * size - 1)

def alph2bit(alph):
	return 1 << ord(alph) - ord('a')

def update(i, x, segment_tree):
	i += size - 1
	segment_tree[i] = alph2bit(x)
	while i > 0:
		i = (i - 1) // 2
		segment_tree[i] = segment_tree[i * 2 + 1] | segment_tree[i * 2 + 2]

def query(s, t, k, l, r, segment_tree):
	if r <= s or t <= l:
		return 0
	if s <= l and r <= t:
		return segment_tree[k]
	else:
		ask_left = query(s, t, k * 2 + 1, l, (l + r) // 2, segment_tree)
		ask_right = query(s, t, k * 2 + 2, (l + r) // 2, r, segment_tree)
		return ask_left | ask_right
for i in range(n):
	update(i, s[i], seg)
for (t, a, b) in queris:
	if t == '1':
		update(int(a) - 1, b, seg)
	else:
		result = query(int(a) - 1, int(b), 0, 0, size, seg)
		print(bin(result).count('1'))


import sys

def input():
	return sys.stdin.readline().rstrip()

class SegmentTree:
	__slots__ = ['func', 'e', 'original_size', 'n', 'data']

	def __init__(self, length_or_list, func, e):
		self.func = func
		self.e = e
		if isinstance(length_or_list, int):
			self.original_size = length_or_list
			self.n = 1 << (length_or_list - 1).bit_length()
			self.data = [self.e] * self.n
		else:
			self.original_size = len(length_or_list)
			self.n = 1 << (self.original_size - 1).bit_length()
			self.data = [self.e] * self.n + length_or_list + [self.e] * (self.n - self.original_size)
			for i in range(self.n - 1, 0, -1):
				self.data[i] = self.func(self.data[2 * i], self.data[2 * i + 1])

	def replace(self, index, value):
		index += self.n
		self.data[index] = value
		index //= 2
		while index > 0:
			self.data[index] = self.func(self.data[2 * index], self.data[2 * index + 1])
			index //= 2

	def folded(self, l, r):
		left_folded = self.e
		right_folded = self.e
		l += self.n
		r += self.n
		while l < r:
			if l % 2:
				left_folded = self.func(left_folded, self.data[l])
				l += 1
			if r % 2:
				r -= 1
				right_folded = self.func(self.data[r], right_folded)
			l //= 2
			r //= 2
		return self.func(left_folded, right_folded)

	def all_folded(self):
		return self.data[1]

	def __getitem__(self, index):
		return self.data[self.n + index]

	def max_right(self, l, f):
		if l >= self.original_size:
			return self.original_size
		l += self.n
		left_folded = self.e
		while True:
			while l % 2 == 0:
				l //= 2
			if not f(self.func(left_folded, self.data[l])):
				while l < self.n:
					l *= 2
					if f(self.func(left_folded, self.data[l])):
						left_folded = self.func(left_folded, self.data[l])
						l += 1
				return l - self.n
			left_folded = self.func(left_folded, self.data[l])
			l += 1
			if l == l & -l:
				break
		return self.original_size

	def min_left(self, r, f):
		if r == 0:
			return 0
		r += self.n
		right_folded = self.e
		while True:
			r //= r & -r
			if not f(self.func(self.data[r], right_folded)):
				while r < self.n:
					r = 2 * r + 1
					if f(self.func(self.data[r], right_folded)):
						right_folded = self.func(self.data[r], right_folded)
						r -= 1
				return r + 1 - self.n
			if r == r & -r:
				break
		return 0

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

def main():
	N = int(input())
	S = input()
	S = list(map(lambda c: 2 ** (ord(c) - ord('a')), list(S)))
	Q = int(input())
	seg = SegmentTree(S, orr, 0)
	for _ in range(Q):
		(num, x, y) = input().split()
		if num == '1':
			seg.replace(int(x) - 1, 2 ** (ord(y) - ord('a')))
		else:
			bits = seg.folded(int(x) - 1, int(y))
			print(sum(map(int, list(bin(bits))[2:])))

def __starting_point():
	main()
__starting_point()


import sys
import bisect
input = sys.stdin.readline
sys.setrecursionlimit(10 ** 6)

def main():
	n = int(input())
	s = list(input().strip())
	q = int(input())
	alpha = g = [[] for _ in range(26)]
	orda = ord('a')
	for i in range(n):
		alpha[ord(s[i]) - orda].append(i)
	for i in range(q):
		(a, b, c) = map(str, input().split())
		if a == '1':
			b = int(b) - 1
			if c != s[b]:
				alpha[ord(s[b]) - orda].remove(b)
				s[b] = c
				bisect.insort(alpha[ord(c) - orda], b)
		else:
			ans = 0
			for i in range(26):
				if len(alpha[i]) > 0:
					it = bisect.bisect_left(alpha[i], int(b) - 1)
					if it < len(alpha[i]) and alpha[i][it] < int(c):
						ans += 1
			print(ans)
main()


from bisect import bisect_left, insort

def main():
	n = int(input())
	s = list(input().rstrip())
	q = int(input())
	ans = []
	al = [[] for _ in range(26)]
	for (i, c) in enumerate(s):
		al[ord(c) - ord('a')].append(i)
	for _ in range(q):
		(x, y, z) = map(str, input().rstrip().split())
		if x == '1':
			y = int(y) - 1
			if s[y] == z:
				continue
			p = bisect_left(al[ord(s[y]) - ord('a')], y)
			al[ord(s[y]) - ord('a')].pop(p)
			insort(al[ord(z) - ord('a')], y)
			s[y] = z
		else:
			y = int(y) - 1
			z = int(z)
			cnt = 0
			for i in range(26):
				index = bisect_left(al[i], y)
				if index < len(al[i]) and al[i][index] < z:
					cnt += 1
			ans.append(cnt)
	for v in ans:
		print(v)
main()


import bisect

def main():
	N = int(input())
	S = list(input())
	Q = int(input())
	L = [[] for x in range(26)]
	for (idx, s) in enumerate(S):
		L[ord(s) - ord('a')].append(idx)
	for _ in range(Q):
		row = input().split()
		if row[0] == '1':
			(y, z) = (int(row[1]) - 1, row[2])
			if S[y] != z:
				idx_target = ord(S[y]) - ord('a')
				idx_del = bisect.bisect_left(L[idx_target], y)
				if idx_del < len(L[idx_target]):
					L[idx_target].pop(idx_del)
				bisect.insort(L[ord(z) - ord('a')], y)
				S[y] = z
		elif row[0] == '2':
			(y, z) = (int(row[1]) - 1, int(row[2]) - 1)
			answer = 0
			for idx_alphabet in range(26):
				left = bisect.bisect_left(L[idx_alphabet], y)
				if left < len(L[idx_alphabet]) and y <= L[idx_alphabet][left] <= z:
					answer += 1
			print(answer)
	pass

def __starting_point():
	main()
__starting_point()


import bisect
from collections import defaultdict
N = int(input())
S = [*input()]
Q = int(input())
d = defaultdict(list)
for (i, c) in enumerate(S):
	d[c] += [i]
for _ in range(Q):
	(q, y, z) = input().split()
	if q == '1':
		i = int(y) - 1
		if S[i] == z:
			continue
		b = bisect.bisect(d[S[i]], i)
		d[S[i]].pop(b - 1)
		S[i] = z
		bisect.insort(d[z], i)
	else:
		left = int(y) - 1
		right = int(z) - 1
		count = 0
		for v in d.values():
			count += 1 if bisect.bisect(v, right) - bisect.bisect_left(v, left) > 0 else 0
		print(count)


import sys
input = sys.stdin.readline
n = int(input())
data = [0] * (2 * n)

def upd(i, x):
	i += n
	data[i] = x
	while i > 1:
		data[i >> 1] = data[i] | data[i ^ 1]
		i >>= 1

def qry(l, r):
	l += n
	r += n
	res = 0
	while l < r:
		if l & 1:
			res |= data[l]
			l += 1
		if r & 1:
			r -= 1
			res |= data[r]
		l >>= 1
		r >>= 1
	return bin(res).count('1')
for (i, c) in enumerate(input()[:-1], n):
	data[i] = 1 << ord(c) - ord('a')
for i in range(n - 1, 0, -1):
	data[i] = data[i << 1] | data[i << 1 | 1]
ans = []
for _ in range(int(input())):
	(q, a, b) = input().split()
	if int(q) == 1:
		upd(int(a) - 1, 1 << ord(b) - ord('a'))
	else:
		ans.append(qry(int(a) - 1, int(b)))
print('\n'.join(map(str, ans)))


import bisect
N = int(input())
S = list(str(input()))

def ordN(x):
	return ord(x) - ord('a')
li = [[] for _ in range(26)]
for (i, s) in enumerate(S):
	li[ordN(s)].append(i)
for i in range(int(input())):
	(Q1, Q2, Q3) = input().split()
	if Q1 == '1':
		Q2 = int(Q2) - 1
		if S[Q2] != Q3:
			I = bisect.bisect_left(li[ordN(S[Q2])], Q2)
			li[ordN(S[Q2])].pop(I)
			bisect.insort(li[ordN(Q3)], Q2)
			S[Q2] = Q3
	else:
		(Q2, Q3) = (int(Q2) - 1, int(Q3) - 1)
		count = 0
		for j in range(26):
			I = bisect.bisect_left(li[j], Q2)
			if I < len(li[j]) and li[j][I] <= Q3:
				count += 1
		print(count)


def update(i, x):
	i += d - 1
	bit = ord(x) - 97
	seg[i] = 0 | 1 << bit
	while i > 0:
		i = (i - 1) // 2
		seg[i] = seg[i * 2 + 1] | seg[i * 2 + 2]

def find(a, b, k, l, r):
	if r <= a or b <= l:
		return 0
	if a <= l and r <= b:
		return seg[k]
	c1 = find(a, b, 2 * k + 1, l, (l + r) // 2)
	c2 = find(a, b, 2 * k + 2, (l + r) // 2, r)
	return c1 | c2
n = int(input())
s = input()
q = int(input())
d = 1
while d < n:
	d *= 2
seg = [0] * (2 * d - 1)
for i in range(n):
	update(i, s[i])
for i in range(q):
	(type, a, b) = input().split()
	if type == '1':
		update(int(a) - 1, b)
	else:
		part = find(int(a) - 1, int(b), 0, 0, d)
		print(bin(part).count('1'))


n = int(input())
s = list(input())
q = int(input())
bits = [[0 for _ in range(n + 1)] for _ in range(26)]
sl = []
for alp in s:
	alpord = ord(alp) - 97
	sl.append(alpord)

def query(pos):
	ret = [0] * 26
	p = pos
	while p > 0:
		for i in range(26):
			ret[i] += bits[i][p]
		p -= p & -p
	return ret

def update(pos, a, x):
	r = pos
	while r <= n:
		bits[a][r] += x
		r += r & -r
for i in range(n):
	update(i + 1, sl[i], 1)
for _ in range(q):
	(quer, xx, yy) = map(str, input().split())
	if quer == '1':
		x = int(xx)
		y = ord(yy) - 97
		if sl[x - 1] == y:
			continue
		else:
			update(x, sl[x - 1], -1)
			update(x, y, 1)
			sl[x - 1] = y
	else:
		x = int(xx)
		y = int(yy)
		cnt1 = query(y)
		cnt2 = query(x - 1)
		ans = 0
		for i in range(26):
			if cnt1[i] - cnt2[i] > 0:
				ans += 1
		print(ans)


from collections import defaultdict
from bisect import bisect_left, insort_left
import sys
input = sys.stdin.readline
N = int(input())
S = list(input())
dic = defaultdict(list)
for (i, s) in enumerate(S):
	dic[s].append(i)
Q = int(input())
for _ in [0] * Q:
	(t, *q) = input().split()
	if t == '1':
		(i, c) = q
		i = int(i) - 1
		s = S[i]
		if s == c:
			continue
		S[i] = c
		dic[s].pop(bisect_left(dic[s], i))
		insort_left(dic[c], i)
	else:
		(l, r) = map(int, q)
		l -= 1
		r -= 1
		cnt = 0
		for L in dic.values():
			i = bisect_left(L, l)
			if i != len(L) and L[i] <= r:
				cnt += 1
		print(cnt)


def popcount(x):
	return bin(x).count('1')

def initialize(N):
	i = 1
	while i < N:
		i *= 2
	return ([0] * (2 * i - 1), i)

def update(i, x):
	i += d - 1
	bit = ord(x) - 97
	SEG[i] = 0 | 1 << bit
	while i > 0:
		i = (i - 1) // 2
		SEG[i] = SEG[i * 2 + 1] | SEG[i * 2 + 2]

def find(a, b, k, l, r):
	if r <= a or b <= l:
		return 0
	if a <= l and r <= b:
		return SEG[k]
	else:
		c1 = find(a, b, 2 * k + 1, l, (l + r) // 2)
		c2 = find(a, b, 2 * k + 2, (l + r) // 2, r)
		return c1 | c2
N = int(input())
S = input()
Q = int(input())
(SEG, d) = initialize(N)
for i in range(N):
	update(i, S[i])
for i in range(Q):
	(com, s, t) = map(str, input().split())
	if com == '1':
		update(int(s) - 1, t)
	else:
		print(popcount(find(int(s) - 1, int(t), 0, 0, d)))


import bisect
N = int(input())
indexess = [[] for _ in range(26)]
S = list(input())
for (i, s) in enumerate(S):
	indexess[ord(s) - 97].append(i)
Q = int(input())
for _ in range(Q):
	(q1, q2, q3) = input().split()
	q2 = int(q2)
	if q1 == '1':
		s0 = S[q2 - 1]
		if s0 != q3:
			S[q2 - 1] = q3
			indexes = indexess[ord(s0) - 97]
			del indexes[bisect.bisect_left(indexes, q2 - 1)]
			bisect.insort(indexess[ord(q3) - 97], q2 - 1)
	else:
		cnt = 0
		q3 = int(q3)
		for indexes in indexess:
			if bisect.bisect_left(indexes, q2 - 1) < bisect.bisect_right(indexes, q3 - 1):
				cnt += 1
		print(cnt)


from math import log2, ceil

class SegTree:
	ide_ele = 0

	def __init__(self, init_val):
		n = len(init_val)
		self.num = 2 ** ceil(log2(n))
		self.seg = [self.ide_ele] * (2 * self.num - 1)
		for i in range(n):
			self.seg[i + self.num - 1] = init_val[i]
		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 segfunc(self, x, y):
		return x | y

	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, a, b, k, l, r):
		if r <= a or b <= l:
			return self.ide_ele
		if a <= l and r <= b:
			return self.seg[k]
		else:
			vl = self.query(a, b, k * 2 + 1, l, (l + r) // 2)
			vr = self.query(a, b, k * 2 + 2, (l + r) // 2, r)
			return self.segfunc(vl, vr)
N = int(input())
S = input()
Q = int(input())
li = [1 << ord(s) - ord('a') for s in S]
seg_tree = SegTree(li)
ans = []
for _ in range(Q):
	(i, l, r) = input().split()
	i = int(i)
	l = int(l)
	if i == 1:
		seg_tree.update(l - 1, 1 << ord(r) - ord('a'))
	else:
		r = int(r)
		num = seg_tree.query(l - 1, r, 0, 0, seg_tree.num)
		ans.append(bin(num).count('1'))
for a in ans:
	print(a)


class SegT:

	def __init__(self, size):
		self.size = 1
		while self.size < size:
			self.size *= 2
		self.data = [0] * (self.size * 2 - 1)

	def update(self, i, x):
		i += self.size - 1
		self.data[i] = x
		while i > 0:
			i = (i - 1) // 2
			self.data[i] = self.data[i * 2 + 1] | self.data[i * 2 + 2]

	def get(self, a, b, node=0, l=0, r=-1):
		if r < 0:
			r = self.size
		if r <= a or b <= l:
			return 0
		if a <= l and r <= b:
			return self.data[node]
		vl = self.get(a, b, node * 2 + 1, l, (l + r) // 2)
		vr = self.get(a, b, node * 2 + 2, (l + r) // 2, r)
		return vl | vr
N = int(input())
S = input()
Q = int(input())
segt = SegT(N)
for i in range(N):
	x = ord(S[i]) - ord('a')
	segt.update(i, 1 << x)
for i in range(Q):
	(t, l, r) = input().split()
	if t == '1':
		x = ord(r) - ord('a')
		segt.update(int(l) - 1, 1 << x)
	else:
		x = segt.get(int(l) - 1, int(r))
		ans = 0
		for i in range(26):
			if x >> i & 1:
				ans += 1
		print(ans)


import sys
input = lambda : sys.stdin.readline().rstrip()

class SegTree:

	def __init__(self, init_val, segfunc, ide_ele):
		n = len(init_val)
		self.ide_ele = ide_ele
		self.segfunc = segfunc
		self.num = 2 ** (n - 1).bit_length()
		self.seg = [self.ide_ele] * 2 * self.num
		for i in range(n):
			self.seg[i + self.num - 1] = init_val[i]
		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 solve():
	N = int(input())
	S = list(input())
	Q = int(input())
	seg = [1 << ord(s) - ord('a') for s in S]
	segtree = []
	segfunc = lambda a, b: a | b
	segtree = SegTree(seg, segfunc, 0)
	ans = []
	for i in range(Q):
		(a, b, c) = input().split()
		a = int(a)
		if a == 1:
			b = int(b) - 1
			al = ord(c) - ord('a')
			segtree.update(b, 1 << al)
		elif a == 2:
			(b, c) = (int(b) - 1, int(c))
			res = segtree.query(b, c)
			res = sum(list(map(int, bin(res)[2:])))
			ans.append(res)
	print('\n'.join(map(str, ans)))

def __starting_point():
	solve()
__starting_point()


class SegmentTree(object):

	def __init__(self, sequence, function, identity):
		N = len(sequence)
		self.length = (1 << N - 1).bit_length()
		self.function = function
		self.data = [identity] * (self.length << 1)
		self.identity = identity
		for i in range(N):
			self.data[i + self.length - 1] = sequence[i]
		for i in range(self.length - 2, -1, -1):
			self.data[i] = self.function(self.data[(i << 1) + 1], self.data[(i << 1) + 2])

	def update(self, idx, x):
		idx += self.length - 1
		self.data[idx] = x
		while idx:
			idx = idx - 1 >> 1
			self.data[idx] = self.function(self.data[(idx << 1) + 1], self.data[(idx << 1) + 2])

	def query(self, p, q):
		if q <= p:
			return self.identity
		p += self.length - 1
		q += self.length - 2
		res = self.identity
		while q - p > 1:
			if not p & 1:
				res = self.function(res, self.data[p])
			if q & 1:
				res = self.function(res, self.data[q])
				q -= 1
			p >>= 1
			q = q - 1 >> 1
		return self.function(res, self.data[p]) if p == q else self.function(self.function(res, self.data[p]), self.data[q])

def popcount(n):
	n = (n & 6148914691236517205) + ((n & 12297829382473034410) >> 1)
	n = (n & 3689348814741910323) + ((n & 14757395258967641292) >> 2)
	n = (n & 1085102592571150095) + ((n & 17361641481138401520) >> 4)
	n = (n & 71777214294589695) + ((n & 18374966859414961920) >> 8)
	n = (n & 281470681808895) + ((n & 18446462603027742720) >> 16)
	n = (n & 4294967295) + ((n & 18446744069414584320) >> 32)
	return n
N = int(input())
S = input()
atoi = {chr(ord('a') + d): 1 << d for d in range(26)}
data = [atoi[c] for c in S]
seg_tree = SegmentTree(data, lambda a, b: a | b, 0)
Q = int(input())
for _ in range(Q):
	(q, a, b) = input().split()
	if q == '1':
		idx = int(a) - 1
		seg_tree.update(idx, atoi[b])
	else:
		print(popcount(seg_tree.query(int(a) - 1, int(b))))


from bisect import bisect_left, insort_left

def main():
	n = int(input())
	s = list(input())
	q = int(input())
	qs = [input().split() for _ in range(q)]
	abc = [[] for _ in range(26)]
	for (i, e) in enumerate(s):
		j = ord(e) - ord('a')
		abc[j].append(i)
	for (t, e1, e2) in qs:
		if t == '1':
			i = int(e1) - 1
			c = e2
			let = s[i]
			if let == c:
				continue
			idx = ord(let) - ord('a')
			popi = bisect_left(abc[idx], i)
			abc[idx].pop(popi)
			idx = ord(c) - ord('a')
			insort_left(abc[idx], i)
			s[i] = c
		else:
			l = int(e1) - 1
			r = int(e2) - 1
			cnt = 0
			for i in range(26):
				li = bisect_left(abc[i], l)
				if li >= len(abc[i]):
					continue
				if abc[i][li] <= r:
					cnt += 1
			print(cnt)
main()


def segfunc(x, y):
	return set(x) | set(y)
ide_ele = set()

class SegTree:

	def __init__(self, init_val, segfunc, ide_ele):
		n = len(init_val)
		self.segfunc = segfunc
		self.ide_ele = ide_ele
		self.num = 1 << (n - 1).bit_length()
		self.tree = [ide_ele] * 2 * self.num
		for i in range(n):
			self.tree[self.num + i] = init_val[i]
		for i in range(self.num - 1, 0, -1):
			self.tree[i] = self.segfunc(self.tree[2 * i], self.tree[2 * i + 1])

	def update(self, k, x):
		k += self.num
		self.tree[k] = x
		while k > 1:
			self.tree[k >> 1] = self.segfunc(self.tree[k], self.tree[k ^ 1])
			k >>= 1

	def query(self, l, r):
		res = self.ide_ele
		l += self.num
		r += self.num
		while l < r:
			if l & 1:
				res = self.segfunc(res, self.tree[l])
				l += 1
			if r & 1:
				res = self.segfunc(res, self.tree[r - 1])
			l >>= 1
			r >>= 1
		return res
n = int(input())
s = input()
q = int(input())
st = SegTree(s, segfunc, ide_ele)
for _ in range(q):
	(q, c, r) = input().split()
	if q == '1':
		st.update(int(c) - 1, r)
	else:
		print(len(st.query(int(c) - 1, int(r))))


import sys
input = lambda : sys.stdin.readline().rstrip()
sys.setrecursionlimit(max(1000, 10 ** 9))
write = lambda x: sys.stdout.write(x + '\n')
n = int(input())
s = input()
q = int(input())

def init(bit, values):
	for (i, v) in enumerate(values):
		update(bit, i, v)

def query(bit, i):
	res = 0
	while i > 0:
		res += bit[i]
		i -= i & -i
	return res

def update(bit, i, x):
	while i <= len(bit) - 1:
		bit[i] += x
		i += i & -i
	return
l = [chr(v) for v in range(ord('a'), ord('z') + 1)]
d = {c: [0] * (n + 1) for c in l}
for (i, c) in enumerate(s):
	update(d[c], i + 1, 1)
s = list(s)
ans = []
for i in range(q):
	(v, i, c) = input().split()
	if v == '1':
		i = int(i) - 1
		if d[s[i]][i + 1] >= 1:
			update(d[s[i]], i + 1, -1)
		update(d[c], i + 1, 1)
		s[i] = c
	else:
		(ll, rr) = (int(i), int(c))
		val = sum((query(d[c], rr) - query(d[c], ll - 1) >= 1 for c in l))
		ans.append(val)
write('\n'.join(map(str, ans)))


N = int(input())
s = input()
N0 = 1
while N0 <= N:
	N0 *= 2
INF = 0
data = [0] * (2 * N0)

def update(k, x):
	k += N0 - 1
	data[k] = 1 << x
	while k >= 0:
		k = (k - 1) // 2
		data[k] = data[2 * k + 1] | data[2 * k + 2]

def query(l, r):
	L = l + N0
	R = r + N0
	s = INF
	while L < R:
		if R & 1:
			R -= 1
			s = s | data[R - 1]
		if L & 1:
			s = s | data[L - 1]
			L += 1
		L >>= 1
		R >>= 1
	return s
for i in range(N):
	update(i, ord(s[i]) - ord('a'))
q = int(input())
for j in range(q):
	(t, l, r) = input().split()
	if t == '1':
		update(int(l) - 1, ord(r) - ord('a'))
	else:
		bit = bin(query(int(l) - 1, int(r)))[2:]
		ans = 0
		for i in bit:
			ans += int(i)
		print(ans)


class Segment_tree:

	def __init__(self, n, s):
		self.alphabet_list = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
		self.key = dict()
		self.k = 1
		for value in self.alphabet_list:
			self.key[value] = self.k
			self.k *= 2
		self.inf = pow(2, 32)
		self.n = n
		self.s = s
		self.N = 1
		while self.N < self.n:
			self.N *= 2
		self.size = self.N * 2
		self.size -= 1
		self.N -= 1
		self.segment = [0] * self.N + [self.key[self.s[i]] for i in range(self.n)] + [0] * (self.size - self.N - self.n)
		for i in range(self.N - 1, -1, -1):
			self.segment[i] = self.segment[2 * i + 1] | self.segment[2 * i + 2]

	def update(self, i, x):
		i += self.N - 1
		self.segment[i] = self.key[x]
		while i > 0:
			i = (i - 1) // 2
			self.segment[i] = self.segment[2 * i + 1] | self.segment[2 * i + 2]

	def find(self, a, b, k, l, r):
		if r <= a or b <= l:
			return 0
		elif a <= l and r <= b:
			return self.segment[k]
		else:
			find_l = self.find(a, b, 2 * k + 1, l, (l + r) // 2)
			find_r = self.find(a, b, 2 * k + 2, (l + r) // 2, r)
			return find_l | find_r
n = int(input())
s = input()
segment = Segment_tree(n, s)
q = int(input())
N = 1
while N < n:
	N *= 2
for i in range(q):
	quer = [x for x in input().split()]
	if quer[0] == '1':
		(i, c) = (int(quer[1]), quer[2])
		segment.update(i, c)
	else:
		(l, r) = (int(quer[1]), int(quer[2]))
		key = segment.find(l - 1, r, 0, 0, N)
		ans = 0
		for i in range(26):
			if key >> i & 1:
				ans += 1
		print(ans)


class BIT:

	def __init__(self, n):
		self.N = n
		self.data = [0] * (N + 1)

	def bit_add(self, i, a):
		j = i + 1
		while j <= N:
			self.data[j] += a
			j += j & -j

	def bit_sum(self, i):
		m = 0
		j = i + 1
		while j > 0:
			m += self.data[j]
			j -= j & -j
		return m
N = int(input())
S = list(input())
Q = int(input())
dic = [0] * 26
s = ord('a')
for i in range(26):
	dic[i] = BIT(N)
for (i, c) in enumerate(S):
	c = ord(c) - s
	dic[c].bit_add(i, 1)
for i in range(Q):
	(t, a, b) = input().split()
	t = int(t)
	if t == 1:
		a = int(a) - 1
		c = S[a]
		S[a] = b
		b = ord(b) - s
		c = ord(c) - s
		dic[b].bit_add(a, 1)
		dic[c].bit_add(a, -1)
	else:
		a = int(a)
		b = int(b)
		ans = 0
		a -= 1
		b -= 1
		for i in range(26):
			if a > 0:
				z = dic[i].bit_sum(b) - dic[i].bit_sum(a - 1)
			else:
				z = dic[i].bit_sum(b)
			if z > 0:
				ans += 1
		print(ans)


from string import ascii_lowercase
from bisect import bisect_left, insort
from collections import defaultdict
N = int(input())
S = list(input())
Q = int(input())
locs = {c: [] for c in ascii_lowercase}
for i in range(N):
	locs[S[i]].append(i + 1)
for _ in range(Q):
	(qt, l, r) = input().split()
	l = int(l)
	if int(qt) == 1:
		if S[l - 1] != r:
			locs[S[l - 1]].remove(l)
			S[l - 1] = r
			insort(locs[r], l)
	else:
		count = 0
		r = int(r)
		for ch in ascii_lowercase:
			if len(locs[ch]) > 0:
				left = bisect_left(locs[ch], l)
				if left != len(locs[ch]):
					if locs[ch][left] <= r:
						count += 1
		print(count)


import bisect
n = int(input())
s = list(input())
alpha = {chr(i): [] for i in range(97, 123)}
for (i, c) in enumerate(s):
	bisect.insort(alpha[c], i + 1)
for i in range(int(input())):
	(p, q, r) = input().split()
	if p == '1':
		q = int(q)
		b = s[q - 1]
		if b != r:
			alpha[b].pop(bisect.bisect_left(alpha[b], q))
			bisect.insort(alpha[r], q)
			s[q - 1] = r
	else:
		count = 0
		for l in alpha.values():
			pos = bisect.bisect_left(l, int(q))
			if pos < len(l) and l[pos] <= int(r):
				count += 1
		print(count)


def segfunc(x, y):
	return x | y
ide_ele = 0

class SegTree:

	def __init__(self, init_val, segfunc, ide_ele):
		n = len(init_val)
		self.segfunc = segfunc
		self.ide_ele = ide_ele
		self.num = 1 << (n - 1).bit_length()
		self.tree = [ide_ele] * 2 * self.num
		for i in range(n):
			self.tree[self.num + i] = init_val[i]
		for i in range(self.num - 1, 0, -1):
			self.tree[i] = self.segfunc(self.tree[2 * i], self.tree[2 * i + 1])

	def update(self, k, x):
		k += self.num
		self.tree[k] = x
		while k > 1:
			self.tree[k >> 1] = self.segfunc(self.tree[k], self.tree[k ^ 1])
			k >>= 1

	def query(self, l, r):
		res = self.ide_ele
		l += self.num
		r += self.num
		while l < r:
			if l & 1:
				res = self.segfunc(res, self.tree[l])
				l += 1
			if r & 1:
				res = self.segfunc(res, self.tree[r - 1])
			l >>= 1
			r >>= 1
		return res
n = int(input())
s = input()
q = int(input())
ls = []
for ch in s:
	ls.append(1 << ord(ch) - 97)
seg = SegTree(ls, segfunc, ide_ele)
for i in range(q):
	que = input().split()
	if que[0] == '1':
		iq = int(que[1])
		cq = que[2]
		seg.update(iq - 1, 1 << ord(cq) - 97)
	else:
		lq = int(que[1])
		rq = int(que[2])
		ret = seg.query(lq - 1, rq)
		print(str(bin(ret)).count('1'))


from bisect import bisect_left, bisect_right, insort
N = int(input())
S = list(input())
Q = int(input())
D = dict()
D2 = dict()
D3 = dict()
for i in range(97, 97 + 26):
	D[chr(i)] = []
	D2[chr(i)] = []
	D3[chr(i)] = []
for i in range(N):
	D[S[i]].append(i + 1)
for i in range(Q):
	(t, l, r) = input().split()
	if t == str(1):
		k = int(l)
		c = r
		if S[k - 1] == c:
			continue
		if bisect_right(D[S[k - 1]], k) - bisect_left(D[S[k - 1]], k) == 1:
			del D[S[k - 1]][bisect_left(D[S[k - 1]], k)]
		insort(D[c], k)
		S[k - 1] = c
		continue
	l = int(l)
	r = int(r)
	ans = 0
	for i in range(97, 97 + 26):
		X = D[chr(i)]
		X2 = D2[chr(i)]
		X3 = D3[chr(i)]
		if bisect_right(X, r) - bisect_left(X, l) > 0:
			ans += 1
	print(ans)


import sys
input = sys.stdin.readline

class BIT:

	def __init__(self, size):
		self.bit = [0] * (size + 1)
		self.size = size

	def sum(self, i):
		i += 1
		s = 0
		while i > 0:
			s += self.bit[i]
			i -= i & -i
		return s

	def add(self, i, x):
		i += 1
		while i <= self.size:
			self.bit[i] += x
			i += i & -i
N = int(input())
S = list(input().rstrip())
bits = [BIT(N) for _ in range(26)]
for i in range(N):
	bits[ord(S[i]) - ord('a')].add(i, 1)
Q = int(input())
for _ in range(Q):
	(t, x, y) = input().split()
	if t == '1':
		i = int(x) - 1
		c = y
		bits[ord(S[i]) - ord('a')].add(i, -1)
		bits[ord(c) - ord('a')].add(i, 1)
		S[i] = c
	else:
		l = int(x) - 1
		r = int(y) - 1
		ans = 0
		for i in range(26):
			cnt = bits[i].sum(r) - (bits[i].sum(l - 1) if l > 0 else 0)
			if cnt > 0:
				ans += 1
		print(ans)


n = int(input())
S = list(input())
q = int(input())
import sys
input = sys.stdin.readline
alp = 'abcdefghijklmnopqrstuvwxyz'
appr = {a: [] for a in alp}
import bisect
for (i, a) in enumerate(S):
	appr[a].append(i + 1)
for i in range(q):
	inputs = input().split()
	if inputs[0] == '1':
		c = int(inputs[1])
		a = inputs[2]
		if S[c - 1] == a:
			continue
		else:
			old = S[c - 1]
			S[c - 1] = a
			del_idx = bisect.bisect_left(appr[old], c)
			del appr[old][del_idx]
			in_idx = bisect.bisect_left(appr[a], c)
			appr[a].insert(in_idx, c)
	else:
		(l, r) = map(int, inputs[1:])
		res = 0
		for a in appr:
			l_idx = bisect.bisect_left(appr[a], l)
			if l_idx < len(appr[a]):
				if appr[a][l_idx] <= r:
					res += 1
		print(res)


from bisect import bisect_left, bisect_right, insort
n = int(input())
s = list('-' + str(input()))
lis = [[] for i in range(26)]
for i in range(1, n + 1):
	num = ord(s[i]) - ord('a')
	lis[num].append(i)
q = int(input())
for turn in range(q):
	query = list(map(str, input().split()))
	if query[0] == '1':
		a = int(query[1])
		if s[a] == query[2]:
			continue
		num = ord(s[a]) - ord('a')
		lis[num].pop(bisect_left(lis[num], a))
		next = ord(query[2]) - ord('a')
		insort(lis[next], a)
		s[a] = query[2]
	else:
		(a, b) = (int(query[1]), int(query[2]))
		ans = 0
		for alphabet in range(26):
			if bisect_right(lis[alphabet], b) - bisect_left(lis[alphabet], a) >= 1:
				ans += 1
		print(ans)


class SegmentTree:

	def __init__(self, n, segment_func, identity_element):
		self.n = n
		self.num = 1 << (self.n - 1).bit_length()
		self.segment_func = segment_func
		self.identity_element = identity_element
		self.segment_tree = [self.identity_element] * (2 * self.num)

	def initialize(self, val_arr):
		for i in range(self.n):
			self.segment_tree[self.num + i] = val_arr[i]
		for i in range(self.num - 1, 0, -1):
			self.segment_tree[i] = self.segment_func(self.segment_tree[2 * i], self.segment_tree[2 * i + 1])

	def update(self, idx, val):
		idx += self.num
		self.segment_tree[idx] = val
		while idx > 1:
			self.segment_tree[idx >> 1] = self.segment_func(self.segment_tree[idx], self.segment_tree[idx ^ 1])
			idx >>= 1

	def query(self, left, right):
		res = self.identity_element
		left += self.num
		right += self.num
		while left < right:
			if left & 1:
				res = self.segment_func(res, self.segment_tree[left])
				left += 1
			if right & 1:
				res = self.segment_func(res, self.segment_tree[right - 1])
			left >>= 1
			right >>= 1
		return res

	def bisect_left(self, left, right, target):
		left += self.num
		right += self.num
		left_min = -1
		right_min = -1
		while left < right:
			if left & 1:
				if self.segment_tree[left] >= target and left_min == -1:
					left_min = left
				left += 1
			if right & 1:
				if self.segment_tree[right - 1] >= target:
					right_min = right - 1
			left >>= 1
			right >>= 1
		if left_min != -1 or right_min != -1:
			res = left_min if left_min != -1 else right_min
			while res < self.num:
				if self.segment_tree[2 * res] >= target:
					res *= 2
				else:
					res *= 2
					res += 1
			return res - self.num
		else:
			return self.n

	def get_val(self, idx):
		return self.segment_tree[self.num + idx]

def conv_to_int(x):
	return 1 << ord(x) - ord('a')

def main():
	n = int(input())
	s = [conv_to_int(t) for t in list(input())]
	q = int(input())
	st = SegmentTree(n, lambda x, y: x | y, 0)
	st.initialize(s)
	for _ in range(q):
		query = input().split()
		if query[0] == '1':
			st.update(int(query[1]) - 1, conv_to_int(query[2]))
		else:
			res = st.query(int(query[1]) - 1, int(query[2]))
			ans = 0
			while res:
				ans += res & 1
				res >>= 1
			print(ans)

def __starting_point():
	main()
__starting_point()