AtCoder Beginner Contest 157 - Simple String Queries

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.

Source: atcoder | Difficulty: MEDIUM


Solutions:
def main():
	import sys
	(n, s, _, *t) = sys.stdin.buffer.read().split()
	n = int(n)
	d = [0] * n + [1 << c - 97 for c in s]
	for i in range(n - 1, 0, -1):
		d[i] = d[i + i] | d[i - ~i]
	for (q, a, b) in zip(*[iter(t)] * 3):
		(i, s) = (int(a) + n - 1, 0)
		if q < b'2':
			d[i] = 1 << ord(b) - 97
			while i > 1:
				i //= 2
				d[i] = d[i + i] | d[i - ~i]
			continue
		j = int(b) + n
		while i < j:
			if i & 1:
				s |= d[i]
				i += 1
			if j & 1:
				j -= 1
				s |= d[j]
			i //= 2
			j //= 2
		print(bin(s).count('1'))
main()


def main():
	import sys
	b = sys.stdin.buffer
	input = b.readline
	n = int(input())
	d = [0] * n + [1 << c - 97 for c in input()[:n]]
	for i in range(n - 1, 0, -1):
		d[i] = d[i + i] | d[i - ~i]
	r = []
	input()
	for (q, a, b) in zip(*[iter(b.read().split())] * 3):
		(i, s) = (int(a) + n - 1, 0)
		if q < b'2':
			d[i] = 1 << b[0] - 97
			while i:
				i >>= 1
				d[i] = d[i + i] | d[i - ~i]
			continue
		j = int(b) + n
		while i < j:
			if i & 1:
				s |= d[i]
				i += 1
			if j & 1:
				j -= 1
				s |= d[j]
			i >>= 1
			j >>= 1
		r += (bin(s).count('1'),)
	print(' '.join(map(str, r)))
main()


import bisect
N = int(input())
S = list(str(input()))
pos = [[] for _ in range(26)]
for (x, s) in enumerate(S):
	num = ord(s) - ord('a')
	pos[num].append(x)
q = int(input())
for _ in range(q):
	(m, a, b) = map(str, input().split())
	if m == '1':
		a = int(a) - 1
		if S[a] == b:
			continue
		else:
			popind = bisect.bisect_left(pos[ord(S[a]) - ord('a')], a)
			pos[ord(S[a]) - ord('a')].pop(popind)
			bisect.insort(pos[ord(b) - ord('a')], a)
			S[a] = b
	else:
		(a, b) = (int(a) - 1, int(b) - 1)
		count = 0
		for i in range(26):
			l = bisect.bisect_left(pos[i], a)
			if l >= len(pos[i]):
				continue
			if pos[i][l] <= b:
				count += 1
		print(count)


import sys
input = sys.stdin.readline
n = int(input())
s = input()
num = 2 ** (n - 1).bit_length()

def segfunc(x, y):
	return x | y
seg = [0] * (2 * num - 1)
for i in range(n):
	seg[i + num - 1] = 2 ** (ord(s[i]) - 97)
for i in range(num - 2, -1, -1):
	seg[i] = segfunc(seg[2 * i + 1], seg[2 * i + 2])

def update(i, x):
	i += num - 1
	seg[i] = x
	while i:
		i = (i - 1) // 2
		seg[i] = segfunc(seg[i * 2 + 1], seg[i * 2 + 2])

def query(l, r):
	l += num - 1
	r += num - 1
	if l == r:
		return seg[l]
	s = seg[l]
	l += 1
	while r - l > 1:
		if ~l % 2:
			s = segfunc(seg[l], s)
		if r % 2:
			s = segfunc(seg[r], s)
			r -= 1
		l //= 2
		r = (r - 1) // 2
	if l == r:
		return segfunc(s, seg[l])
	return segfunc(s, segfunc(seg[l], seg[r]))
for _ in range(int(input())):
	quer = input().split()
	if quer[0] == '1':
		(_, i, c) = quer
		update(int(i) - 1, 2 ** (ord(c) - 97))
	else:
		(_, l, r) = quer
		print(sum(map(int, bin(query(int(l) - 1, int(r) - 1))[2:])))


def bit_add(I, k):
	while I <= N:
		tree[k][I] += 1
		I += I & -I

def bit_no_add(I, k):
	while I <= N:
		tree[k][I] -= 1
		I += I & -I

def bit_sum(I, k):
	s = 0
	while I > 0:
		s += tree[k][I]
		I -= I & -I
	return s
N = int(input())
S = ['a'] + list(input())
Q = int(input())
que = [list(input().split()) for i in range(Q)]
alpa = list('abcdefghijklmnopqrstuvwxyz')
tree = [[0] * (N + 1) for i in range(len(alpa))]
for i in range(1, N + 1):
	j = alpa.index(S[i])
	bit_add(i, j)
for iii in range(Q):
	if que[iii][0] == '1':
		(i, c) = (int(que[iii][1]), que[iii][2])
		j = alpa.index(S[i])
		bit_no_add(i, j)
		S[i] = c
		j = alpa.index(c)
		bit_add(i, j)
	else:
		(l, r) = (que[iii][1], que[iii][2])
		l = int(l)
		r = int(r)
		cnt = 0
		for j in range(len(alpa)):
			if bit_sum(l - 1, j) == bit_sum(r, j):
				continue
			cnt += 1
		print(cnt)


from bisect import bisect_left, bisect_right
N = int(input())
S = list(input())
Q = int(input())
memo = {chr(ord('a') + i): [] for i in range(26)}
for (key, val) in enumerate(S):
	memo[val].append(key)
for q in range(Q):
	query = list(input().split())
	if query[0] == '1':
		(i, x) = (int(query[1]) - 1, query[2])
		now = S[i]
		if now == x:
			continue
		memo[now].remove(i)
		next_i = bisect_left(memo[x], i)
		memo[x].insert(next_i, i)
		S[i] = x
	else:
		(start, end) = (int(query[1]) - 1, int(query[2]) - 1)
		tmp_cout = 0
		for alf_array in memo.values():
			if len(alf_array) == 0:
				continue
			ss = bisect_left(alf_array, start)
			gg = bisect_right(alf_array, end)
			if gg - ss > 0:
				tmp_cout += 1
		print(tmp_cout)


def ctoi(c):
	return ord(c) - 97
n = int(input())
s = list(input())
bits = [[0] * (n + 1) for _ in range(26)]

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, ctoi(s[i]), 1)
q = int(input())
for _ in range(q):
	(flag, a, b) = map(str, 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
	elif flag == 2:
		b = int(b)
		cnt1 = query(b)
		cnt2 = query(a - 1)
		ans = 0
		for i in range(26):
			if cnt1[i] - cnt2[i] > 0:
				ans += 1
		print(ans)


NN = 19
X = [0] * ((1 << NN + 1) - 1)

def popcount(x):
	x -= x >> 1 & 1431655765
	x = (x & 858993459) + (x >> 2 & 858993459)
	x = x + (x >> 4) & 252645135
	x += x >> 8
	x += x >> 16
	return x & 63

def update(a, x):
	i = (1 << NN) - 1 + a
	X[i] = x
	while i:
		i = (i - 1) // 2
		X[i] = X[2 * i + 1] | X[2 * i + 2]

def rangeor(a, b):
	l = a + (1 << NN)
	r = b + (1 << NN)
	x = 0
	while l < r:
		if l % 2:
			x |= X[l - 1]
			l += 1
		if r % 2:
			r -= 1
			x |= X[r - 1]
		l >>= 1
		r >>= 1
	return x
N = int(input())
A = [ord(a) - 97 for a in input()]
for (i, a) in enumerate(A):
	X[(1 << NN) + i] = 1 << a
for i in range((1 << NN) - 1)[::-1]:
	X[i] = X[i * 2 + 1] | X[i * 2 + 2]
Q = int(input())
for _ in range(Q):
	(a, b, c) = input().rstrip().split()
	if a == '1':
		b = int(b)
		c = ord(c) - 97
		update(b, 1 << c)
	else:
		(b, c) = (int(b), int(c))
		print(popcount(rangeor(b, c + 1)))


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')

class BinaryIndexedTree:

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

	def add(self, x, w):
		x += 1
		while x <= self.N:
			self.bit[x] += w
			x += x & -x

	def _sum(self, x):
		ret = 0
		while x > 0:
			ret += self.bit[x]
			x -= x & -x
		return ret

	def sum(self, l, r):
		return self._sum(r) - self._sum(l)
bits = [BinaryIndexedTree(N) for _ in range(26)]
for (i, c) in enumerate(S):
	bits[ctoi(c)].add(i, 1)
s = list(S)
ans = []
for (a, b, c) in qs:
	if a == '1':
		x = int(b) - 1
		bits[ctoi(c)].add(x, 1)
		bits[ctoi(s[x])].add(x, -1)
		s[x] = c
	else:
		(b, c) = (int(b) - 1, int(c))
		tmp = 0
		for i in range(26):
			if bits[i].sum(b, c) > 0:
				tmp += 1
		ans.append(tmp)
print(*ans, sep='\n')


import bisect
n = int(input())
s = list(input())
q = int(input())
pos = [[] for i in range(26)]
alp = 'abcdefghijklmnopqrstuvwxyz'
atoi = {}
for i in range(26):
	atoi[alp[i]] = i
for i in range(n):
	pos[atoi[s[i]]].append(i)
for i in range(q):
	(a, b, c) = input().split()
	if a == '1':
		b = int(b) - 1
		if c == s[b]:
			continue
		index = bisect.bisect_left(pos[atoi[s[b]]], b)
		del pos[atoi[s[b]]][index]
		bisect.insort_left(pos[atoi[c]], b)
		s[b] = c
	else:
		(l, r) = (int(b) - 1, int(c))
		ans = 0
		for i in range(26):
			cnt = bisect.bisect_left(pos[i], r) - bisect.bisect_left(pos[i], l)
			if cnt > 0:
				ans += 1
		print(ans)


import sys
input = sys.stdin.buffer.readline
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:]))
for (i, c) in enumerate(input()[:-1]):
	update(i, 2 ** (c - 97))
for _ in range(int(input())):
	(q, a, b) = input().split()
	if q[0] > 49:
		print(query(int(a) - 1, int(b)))
	else:
		update(int(a) - 1, 2 ** (b[0] - 97))


N = int(input())
S = list(input())
Q = int(input())
l = 2 ** (N - 1).bit_length()
data = [0] * (2 * l)
str2bin = lambda x: 1 << ord(x) - ord('a')
for i in range(N):
	data[l + i] = str2bin(S[i])
for i in range(l - 1, 0, -1):
	data[i] = data[2 * i] | data[2 * i + 1]
for cnt in range(Q):
	(a, b, c) = input().split()
	a = int(a)
	b = int(b)
	if a == 1:
		n = l + b - 1
		data[n] = str2bin(c)
		n //= 2
		while n > 0:
			data[n] = data[2 * n] | data[2 * n + 1]
			n = n // 2
	else:
		c = int(c)
		i = b + l - 1
		j = c + l
		res = 0
		while j - i > 0:
			if i & 1:
				res |= data[i]
				i += 1
			if j & 1:
				res |= data[j - 1]
				j -= 1
			i //= 2
			j //= 2
		print(bin(res).count('1'))


N = int(input())
S = list(input())
Q = int(input())
query = [input().split() for _ in range(Q)]
bit = [[0 for _ in range(26)] for _ in range(N + 1)]

def bit_add(i, s):
	ss = ord(s) - ord('a')
	while i <= N:
		bit[i][ss] += 1
		i += i & -i

def bit_add2(i, s):
	ss = ord(s) - ord('a')
	while i <= N:
		bit[i][ss] += -1
		i += i & -i

def bit_sum(i):
	s = [0] * 26
	while i:
		for j in range(26):
			s[j] += bit[i][j]
		i -= i & -i
	return s
for i in range(1, N + 1):
	s = S[i - 1]
	bit_add(i, s)
for (x, y, z) in query:
	if x == '1':
		y = int(y)
		bit_add2(y, S[y - 1])
		bit_add(y, z)
		S[y - 1] = z
	if x == '2':
		answer = 0
		(y, z) = (int(y) - 1, int(z))
		yy = bit_sum(y)
		zz = bit_sum(z)
		for i in range(26):
			if zz[i] - yy[i] > 0:
				answer += 1
		print(answer)


n = int(input())
s = [*input()]
q = int(input())
B = {chr(97 + i): [0] * (n + 1) for i in range(26)}

def bsum(c, i):
	s = 0
	while i:
		s += B[c][i]
		i -= i & -i
	return s

def badd(c, i, x):
	while i <= n:
		B[c][i] += x
		i += i & -i
for (i, c) in enumerate(s):
	badd(c, i + 1, 1)
for _ in range(q):
	(x, y, z) = input().split()
	y = int(y) - 1
	if x == '1':
		badd(s[y], y + 1, -1)
		s[y] = z
		badd(z, y + 1, 1)
	else:
		print(sum((1 for c in B if bsum(c, int(z)) - bsum(c, y))))


import sys
input = sys.stdin.readline
N = int(input())
S = list(input())[:-1]
Q = int(input())

class BIT:

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

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

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

	def get(self, i, j=None):
		if j is None:
			return self.el[i]
		return self.sum(j) - self.sum(i)
fwks = [BIT(N + 1) for _ in range(26)]
a = ord('a')
for i in range(N):
	j = ord(S[i]) - a
	fwks[j].add(i + 1, 1)
for _ in range(Q):
	(q, x, y) = input().split()
	q = int(q)
	if q == 1:
		x = int(x)
		for i in range(26):
			if fwks[i].get(x):
				fwks[i].add(x, -1)
		fwks[ord(y) - a].add(x, 1)
	else:
		x = int(x)
		y = int(y)
		res = 0
		for i in range(26):
			res += fwks[i].get(x - 1, y) > 0
		print(res)


import sys

def input():
	return sys.stdin.readline().rstrip()
sys.setrecursionlimit(10 ** 7)
import bisect
from string import ascii_lowercase
d = dict()
for (i, c) in enumerate(ascii_lowercase):
	d[c] = i
N = int(input())
S = list(input())
lst = [[] for _ in range(26)]
for i in range(N):
	lst[d[S[i]]].append(i)
Q = int(input())
for q in range(Q):
	(a, b, c) = input().split()
	if a == '1':
		i = int(b) - 1
		if c == S[i]:
			continue
		idx = bisect.bisect_left(lst[d[S[i]]], i)
		del lst[d[S[i]]][idx]
		bisect.insort_left(lst[d[c]], i)
		S[i] = c
	else:
		l = int(b) - 1
		r = int(c)
		ans = 0
		for i in range(26):
			cnt = bisect.bisect_left(lst[i], r) - bisect.bisect_left(lst[i], l)
			if cnt:
				ans += 1
		print(ans)


import sys
input = sys.stdin.readline

def resolve():
	N = int(input())
	S = list(input())
	Q = int(input())
	c0 = ord('a')
	smap = [1 << i - c0 for i in range(c0, ord('z') + 1)]
	T = [0] * N + [smap[ord(S[i]) - c0] for i in range(N)]
	for i in range(N - 1, 0, -1):
		i2 = i << 1
		T[i] = T[i2] | T[i2 | 1]
	ans = []
	for (cmd, i, j) in zip(*[iter(sys.stdin.read().split())] * 3):
		i = int(i) - 1
		if cmd == '1':
			if S[i] == j:
				continue
			S[i] = j
			i0 = N + i
			T[i0] = smap[ord(j) - c0]
			while i0 > 1:
				i0 = i0 >> 1
				T[i0] = T[i0 + i0] | T[i0 - ~i0]
		elif cmd == '2':
			i += N
			j = int(j) + N
			d1 = 0
			while i < j:
				if i & 1:
					d1 |= T[i]
					i += 1
				if j & 1:
					j -= 1
					d1 |= T[j]
				i >>= 1
				j >>= 1
			ans.append(bin(d1).count('1'))
	print(*ans, sep='\n')

def __starting_point():
	resolve()
__starting_point()


import sys
input = sys.stdin.readline

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
x = 'abcdefghijklmnopqrstuvwxyz'
(N,) = map(int, input().split())
d = dict()
for c in x:
	d[c] = Bit(N + 1)
S = list(input().strip())
for (i, c) in enumerate(S):
	d[c].add(i + 1, 1)
Q = int(input())
for _ in range(Q):
	(t, a, b) = input().split()
	if t == '1':
		(i, c) = (int(a), b)
		b = S[i - 1]
		S[i - 1] = c
		d[b].add(i, -1)
		d[c].add(i, 1)
	else:
		(l, r) = (int(a), int(b))
		rr = 0
		for c in x:
			if d[c].sum(r) - d[c].sum(l - 1) > 0:
				rr += 1
		print(rr)


f = input
(n, l, q) = (int(f()), list(f()), int(f()))
B = [[0] * -~n for i in range(26)]

def S(o, i):
	s = 0
	while i:
		s += B[o][i]
		i -= i & -i
	return s

def A(o, i, x):
	while i <= n:
		B[o][i] += x
		i += i & -i
for i in range(n):
	A(ord(l[i]) - 97, i + 1, 1)
for i in range(q):
	(a, b, c) = f().split()
	b = int(b)
	if a > '1':
		print(sum((1 for o in range(26) if S(o, int(c)) - S(o, b - 1))))
	else:
		A(ord(l[b - 1]) - 97, b, -1)
		l[b - 1] = c
		A(ord(c) - 97, b, 1)


import bisect
N = int(input())
S = input()
Q = int(input())
cS = [''] * N
char_idxs = [[] for _ in range(26)]
for (i, s) in enumerate(S):
	cS[i] = s
	char_idxs[ord(s) - 97].append(i)
query = [tuple(map(str, input().split())) for _ in range(Q)]
for (q, a, b) in query:
	if q == '1':
		if cS[int(a) - 1] == b:
			continue
		else:
			idx = bisect.bisect_right(char_idxs[ord(cS[int(a) - 1]) - 97], int(a) - 1)
			if char_idxs[ord(cS[int(a) - 1]) - 97][idx - 1] == int(a) - 1:
				char_idxs[ord(cS[int(a) - 1]) - 97][idx - 1:idx] = []
			bisect.insort_right(char_idxs[ord(b) - 97], int(a) - 1)
			cS[int(a) - 1] = b
	else:
		cnt = 0
		for i in range(26):
			if len(char_idxs[i]) == 0:
				continue
			l = bisect.bisect_left(char_idxs[i], int(a) - 1)
			if l < len(char_idxs[i]) and char_idxs[i][l] <= int(b) - 1:
				cnt += 1
		print(cnt)


from bisect import bisect_left, insort_left
n = int(input())
s = list(input())
lindex = [[] for _ in range(26)]
for i in range(n):
	lindex[ord(s[i]) - 97].append(i)
q = int(input())
for i in range(q):
	(q1, q2, q3) = input().split()
	if q1 == '1':
		q2 = int(q2) - 1
		idx = bisect_left(lindex[ord(s[q2]) - 97], q2)
		if s[q2] != q3:
			del lindex[ord(s[q2]) - 97][idx]
			insort_left(lindex[ord(q3) - 97], q2)
			s[q2] = q3
	else:
		l = int(q2) - 1
		r = int(q3) - 1
		cnt = 0
		for j in range(26):
			if len(lindex[j]) == 0:
				continue
			idx = bisect_left(lindex[j], l)
			if len(lindex[j]) > idx and lindex[j][idx] <= r:
				cnt += 1
		print(cnt)


from bisect import bisect_left, bisect, insort

def main():
	n = int(input())
	s = list(input())
	q = int(input())
	_is = {chr(i): [] for i in range(ord('a'), ord('a') + 27)}
	for (i, si) in enumerate(s):
		_is[si].append(i)
	for _ in range(q):
		(t, i, c) = input().split()
		i = int(i) - 1
		if t == '1':
			if s[i] != c:
				index = bisect_left(_is[s[i]], i)
				del _is[s[i]][index]
				insort(_is[c], i)
				s[i] = c
		else:
			c = int(c) - 1
			cnt = 0
			for _isi in _is.values():
				if _isi:
					is_in = bisect(_isi, c) - bisect_left(_isi, i)
					if is_in:
						cnt += 1
			print(cnt)
main()


import sys
import bisect
N = int(sys.stdin.readline().rstrip())
S = list(sys.stdin.readline().rstrip())
Q = int(sys.stdin.readline().rstrip())
idx = {chr(ord('a') + i): [] for i in range(26)}
for (i, s) in enumerate(S):
	idx[s].append(i + 1)
for _ in range(Q):
	(t, i, c) = sys.stdin.readline().rstrip().split()
	i = int(i)
	if t == '1':
		if S[i - 1] != c:
			idx[S[i - 1]].remove(i)
			bisect.insort(idx[c], i)
			S[i - 1] = c
	else:
		c = int(c)
		ans = 0
		for (a, id) in idx.items():
			x = bisect.bisect_left(id, i)
			y = bisect.bisect_right(id, c)
			if y - x:
				ans += 1
		print(ans)


def main():
	n = int(input())
	s = input()
	Q = int(input())
	t = [input().split() for _ in range(Q)]
	d = [0] * n + [1 << ord(c) - 97 for c in s]
	for i in range(n - 1, 0, -1):
		d[i] = d[i + i] | d[i - ~i]
	for (q, a, b) in t:
		(i, s) = (int(a) + n - 1, 0)
		if q < '2':
			d[i] = 1 << ord(b) - 97
			while i > 1:
				i //= 2
				d[i] = d[i + i] | d[i - ~i]
		else:
			j = int(b) + n
			while i < j:
				if i & 1:
					s |= d[i]
					i += 1
				if j & 1:
					j -= 1
					s |= d[j]
				i //= 2
				j //= 2
			print(bin(s).count('1'))
main()


import sys
input = sys.stdin.readline
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)
import bisect
for _ in range(Q):
	(t, a, b) = input().split()
	a = int(a)
	if int(t) == 1:
		if S[a - 1] != b:
			bag[S[a - 1]].remove(a)
			S[a - 1] = b
			bisect.insort(bag[b], a)
	else:
		count = 0
		b = int(b)
		for l in alphabet:
			if len(bag[l]) > 0:
				left = bisect.bisect_left(bag[l], a)
				if left != len(bag[l]):
					if bag[l][left] <= b:
						count += 1
		print(count)


n = int(input())
ss = input()
dps = ['a'] * n
from collections import defaultdict
d = defaultdict(list)
for i in range(n):
	d[ss[i]].append(i)
	dps[i] = ss[i]
sorted(d.items())
Q = int(input())
import bisect
for i in range(Q):
	(num, ii, c) = input().split()
	if num == '1':
		if c == dps[int(ii) - 1]:
			continue
		bisect.insort_left(d[c], int(ii) - 1)
		d[dps[int(ii) - 1]].remove(int(ii) - 1)
		dps[int(ii) - 1] = c
	else:
		(l, r) = (int(ii) - 1, int(c) - 1)
		count = 0
		for (k, lst) in d.items():
			idx = bisect.bisect_left(lst, l)
			idx1 = bisect.bisect_right(lst, r)
			count += idx1 - idx > 0
		print(count)
		pass


from bisect import bisect_left, bisect_right
N = int(input())
S = list(input())
Q = int(input())
D = {chr(ord('a') + i): [] for i in range(26)}
for (i, s) in enumerate(S):
	D[s].append(i)
for q in range(Q):
	query = list(input().split())
	if query[0] == '1':
		(i, x) = (int(query[1]), query[2])
		i -= 1
		s = S[i]
		if s == x:
			continue
		D[s].remove(i)
		next_i = bisect_left(D[x], i)
		D[x].insert(next_i, i)
		S[i] = x
	if query[0] == '2':
		(l, r) = (int(query[1]), int(query[2]))
		(l, r) = (l - 1, r - 1)
		ans = 0
		for i in range(26):
			s = chr(ord('a') + i)
			li = bisect_left(D[s], l)
			ri = bisect_right(D[s], r)
			if ri - li > 0:
				ans += 1
		print(ans)


import bisect
n = int(input())
s = list(input())
alp = 'abcdefghijklmnopqrstuvwxyz'
cnt = {c: [] for c in alp}
for (i, c) in enumerate(s):
	cnt[c].append(i)
q = int(input())
for _ in range(q):
	(t, x, y) = input().split()
	ans = 0
	if t == '1':
		(i, c) = (int(x) - 1, y)
		if s[i] == c:
			continue
		a = bisect.bisect_left(cnt[s[i]], i)
		cnt[s[i]].pop(a)
		s[i] = c
		b = bisect.bisect_left(cnt[c], i)
		cnt[c].insert(b, i)
	else:
		(l, r) = (int(x) - 1, int(y) - 1)
		for c in alp:
			a = bisect.bisect_left(cnt[c], l)
			if a < len(cnt[c]) and cnt[c][a] <= r:
				ans += 1
		print(ans)


N = int(input())
S = list(input())
Q = int(input())
alphabet = 'abcdefghijklmnopqrstuvwxyz'
num = dict()
for (i, var) in enumerate(alphabet):
	num[var] = i

class Bit:

	def __init__(self, N):
		self.__N = N
		self.__arr = [[0] * 26 for _ in range(1 + N)]

	def add_(self, x, a, i):
		while x < self.__N + 1:
			self.__arr[x][i] += a
			x += x & -x

	def sum_(self, x, i):
		res = 0
		while x > 0:
			res += self.__arr[x][i]
			x -= x & -x
		return res

	def sub_sum_(self, x, y, i):
		return self.sum_(y, i) - self.sum_(x, i)
Bit = Bit(N)
for (i, var) in enumerate(S):
	Bit.add_(i + 1, 1, num[var])
for i in range(Q):
	(q, l, r) = input().split()
	l = int(l)
	if q == '1' and r != S[l - 1]:
		temp = S[l - 1]
		S[l - 1] = r
		Bit.add_(l, -1, num[temp])
		Bit.add_(l, 1, num[r])
	elif q == '2':
		r = int(r)
		res = 0
		for j in range(26):
			res += min(1, Bit.sub_sum_(l - 1, r, j))
		print(res)


def main():
	from bisect import bisect_left, bisect
	n = int(input())
	s = list(input())
	q = int(input())
	al = [[] for i in range(26)]
	for i in range(n):
		al[ord(s[i]) - 97].append(i)
	ans = []
	for i in range(q):
		(a, b, x) = input().split()
		if a == '1':
			al[ord(s[int(b) - 1]) - 97].pop(bisect_left(al[ord(s[int(b) - 1]) - 97], int(b) - 1))
			al[ord(x) - 97].insert(bisect_left(al[ord(x) - 97], int(b) - 1), int(b) - 1)
			s[int(b) - 1] = x
		elif a == '2':
			b = int(b) - 1
			x = int(x) - 1
			cou = 0
			for j in range(26):
				l = bisect_left(al[j], b)
				r = bisect(al[j], x)
				if l != r:
					cou += 1
			ans.append(cou)
	for i in ans:
		print(i)

def __starting_point():
	main()
__starting_point()


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)


def main():
	import sys
	input = sys.stdin.readline
	from bisect import bisect_left, insort_left
	N = int(input())
	S = list(input())
	Q = int(input())
	dic = {chr(i): [] for i in range(ord('a'), ord('z') + 1)}
	for i in range(N):
		dic[S[i]].append(i)
	for _ in range(Q):
		(query, a, c) = input().split()
		if query == '1':
			i = int(a) - 1
			if S[i] == c:
				continue
			ind = bisect_left(dic[S[i]], i)
			dic[S[i]].pop(ind)
			insort_left(dic[c], i)
			S[i] = c
		else:
			(l, r) = (int(a) - 1, int(c) - 1)
			ans = 0
			for inds in dic.values():
				if inds and l <= inds[-1] and (inds[bisect_left(inds, l)] <= r):
					ans += 1
			print(ans)
main()


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.n = n
		self.data = [0] * (n + 1)
		self.el = [0] * (n + 1)

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

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

	def get(self, i, j=None):
		if j is None:
			return self.el[i]
		return self.sum(j) - self.sum(i)
n = int(input())
s = list(input())
q = int(input())
ord_a = ord('a')
queries = [tuple(input().split()) for i in range(q)]
bits = [BIT(n) for i in range(26)]
for (k, v) in enumerate(s, 1):
	bits[ord(v) - ord_a].add(k, 1)
for (query, i, c) in queries:
	if query == '1':
		i = int(i)
		prev = s[i - 1]
		if prev != c:
			bits[ord(prev) - ord_a].add(i, -1)
			bits[ord(c) - ord_a].add(i, 1)
			s[i - 1] = c
	elif query == '2':
		(l, r) = (int(i), int(c))
		res = 0
		for bit in bits:
			if bit.get(r, l - 1):
				res += 1
		print(res)


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
iim = lambda : map(int, input().rstrip().split())

def popcnt2(n):
	a = (0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8)
	ans = 0
	while n:
		ans += a[n & 255]
		n >>= 8
	return ans

def resolve():
	N = int(input())
	S = list(input())
	Q = int(input())
	c0 = ord('a')
	smap = [1 << i - c0 for i in range(c0, ord('z') + 1)]
	T = [0] * N + [smap[ord(S[i]) - c0] for i in range(N)]
	for i in range(N - 1, 0, -1):
		i2 = i << 1
		T[i] = T[i2] | T[i2 | 1]
	ans = []
	for (cmd, i, j) in (line.split() for line in sys.stdin.readlines()):
		i = int(i) - 1
		if cmd == '1':
			if S[i] == j:
				continue
			S[i] = j
			i0 = N + i
			T[i0] = smap[ord(j) - c0]
			while i0 > 1:
				i0 = i0 >> 1
				T[i0] = T[i0 + i0] | T[i0 - ~i0]
		elif cmd == '2':
			i += N
			j = int(j) + N
			d1 = 0
			while i < j:
				if i & 1:
					d1 |= T[i]
					i += 1
				if j & 1:
					j -= 1
					d1 |= T[j]
				i >>= 1
				j >>= 1
			ans.append(popcnt2(d1))
	print(*ans, sep='\n')

def __starting_point():
	resolve()
__starting_point()


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()


f = input
n = int(f())
s = list(f())
d = {chr(97 + i): [0] * (n + 1) for i in range(26)}

def bsum(k, i):
	s = 0
	while i:
		s += d[k][i]
		i -= i & -i
	return s

def badd(k, i, x):
	while i <= n:
		d[k][i] += x
		i += i & -i
for i in range(n):
	badd(s[i], i + 1, 1)
for i in range(int(f())):
	(a, b, c) = f().split()
	b = int(b) - 1
	if a > '1':
		print(sum((1 for k in d.keys() if bsum(k, int(c)) - bsum(k, b))))
	else:
		badd(s[b], b + 1, -1)
		s[b] = c
		badd(c, b + 1, 1)


import sys
read = sys.stdin.read
readline = sys.stdin.readline

class BIT:

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

	def bit_query(self, character, idx):
		if idx == 0:
			return 0
		sum_of_query = 0
		while idx > 0:
			sum_of_query += self.tree[character][idx]
			idx -= idx & -idx
		return sum_of_query

	def update(self, character, idx, x):
		while idx <= self.n:
			self.tree[character][idx] += x
			idx += idx & -idx
		return
N = int(input())
S = [i - 97 for i in map(ord, list(input()))]
S = [-1] + S
(Q, *query) = map(str, read().split())
bit = BIT(N)
for (idx, i) in enumerate(S[1:], 1):
	bit.update(i, idx, 1)
for (a, b, c) in zip(*[iter(query)] * 3):
	b = int(b)
	if a == '1':
		c = ord(c) - 97
		if S[b] == c:
			continue
		bit.update(c, b, 1)
		bit.update(S[b], b, -1)
		S[b] = c
	else:
		c = int(c)
		print(sum((1 for i in range(26) if bit.bit_query(i, c) - bit.bit_query(i, b - 1) > 0)))


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)


N = int(input())
S = input()
L = 20
M = [1 << i for i in range(L)]
T = [[0] * m for m in M]
o = ord('a')
for (i, c) in enumerate(S):
	T[-1][i] = 1 << ord(c) - o
for l in range(L - 2, -1, -1):
	for i in range(M[l]):
		T[l][i] = T[l + 1][i * 2] | T[l + 1][i * 2 + 1]

def q(layer, n, l, r):
	length_block = (1 << L - 1) // M[layer]
	ml = length_block * n
	mr = ml + length_block
	if l == ml and r == mr:
		return T[layer][n]
	center = ml + length_block // 2
	ret = 0
	if l < center:
		ret |= q(layer + 1, n * 2, l, min(r, center))
	if r > center:
		ret |= q(layer + 1, n * 2 + 1, max(l, center), r)
	return ret
Q = int(input())
for _ in range(Q):
	(t, a1, a2) = input().split()
	if t == '1':
		i = int(a1) - 1
		c = a2
		T[-1][i] = 1 << ord(c) - o
		for l in range(L - 2, -1, -1):
			i = i // 2
			T[l][i] = T[l + 1][i * 2] | T[l + 1][i * 2 + 1]
	else:
		l = int(a1) - 1
		r = int(a2)
		x = q(0, 0, l, r)
		ans = 0
		for i in range(26):
			if x >> i & 1:
				ans += 1
		print(ans)


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'))


from operator import or_

class SegmentTree:

	def __init__(self, size, op, e):
		self._op = op
		self._e = e
		self._size = size
		t = 1
		while t < size:
			t *= 2
		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, stop):

		def iter_segments(data, l, r):
			while l < r:
				if l & 1 == 0:
					yield data[l]
				if r & 1 == 0:
					yield data[r - 1]
				l = l // 2
				r = (r - 1) // 2
		op = self._op
		it = iter_segments(self._data, start + self._offset, stop + self._offset)
		result = self._e
		for v in it:
			result = op(result, v)
		return result

def conv(c):
	return 1 << ord(c) - ord('a')
N = int(input())
S = input()
st = SegmentTree(N, or_, 0)
st.build((conv(c) for c in S))
Q = int(input())
for _ in range(Q):
	q = input().split()
	if q[0] == '1':
		(i, c) = q[1:]
		i = int(i) - 1
		st[i] = conv(c)
	elif q[0] == '2':
		(l, r) = list(map(int, q[1:]))
		print(bin(st.query(l - 1, r)).count('1'))


n = int(input())
s = input()
q = int(input())
dic = dict()
for (i, j) in enumerate('qwertyuioplkjhgfdsazxcvbnm'):
	dic[j] = i
No = 2
while n > No:
	No *= 2
tree = [set()] * (2 * No)

def add(k, x):
	k += No - 1
	tree[k] = set([dic[x]])
	while k > 0:
		k = (k - 1) // 2
		tree[k] = tree[2 * k + 1] | tree[2 * k + 2]

def query(l, r):
	L = l + No - 1
	R = r + No - 1
	s = set()
	while L <= R:
		if R & 1:
			s |= tree[R]
			R -= 2
		else:
			R -= 1
		if L & 1:
			L -= 1
		else:
			s |= tree[L]
		L >>= 1
		R >>= 1
	return len(s)
for (i, j) in enumerate(s):
	tree[i + No - 1] = set([dic[j]])
for i in range(No - 2, -1, -1):
	tree[i] = tree[2 * i + 1] | tree[2 * i + 2]
for i in range(q):
	(a, b, c) = input().split()
	(a, b) = (int(a), int(b))
	if a == 1:
		add(b - 1, c)
	if a == 2:
		c = int(c)
		print(query(b - 1, c - 1))


class BIT:

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

	def add(self, val, idx):
		while idx < self.n + 1:
			self.s[idx] = self.s[idx] + val
			idx += idx & -idx
		return

	def get(self, idx):
		res = 0
		while idx > 0:
			res = res + self.s[idx]
			idx -= idx & -idx
		return res
import sys
sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline
n = int(input())
S = [ord(s) - ord('a') for s in input()[:-1]]
bits = [BIT(n) for i in range(26)]
for (i, s) in enumerate(S):
	bits[s].add(1, i + 1)
Q = int(input())
ans = []
for _ in range(Q):
	(flag, x, y) = input().split()
	if flag == '1':
		i = int(x)
		c = ord(y) - ord('a')
		bits[S[i - 1]].add(-1, i)
		bits[c].add(1, i)
		S[i - 1] = c
	else:
		l = int(x)
		r = int(y)
		res = 0
		for i in range(26):
			res += bits[i].get(r) > bits[i].get(l - 1)
		ans.append(str(res))
print('\n'.join(ans))


from bisect import insort_left, bisect_left
N = int(input())
S = list(input())
Q = int(input())
Query = [input() for _ in range(Q)]
dic = {chr(i + ord('a')): [] for i in range(26)}
for (i, s) in enumerate(S):
	dic[s].append(i)
for q in Query:
	(t, a, b) = q.split()
	a = int(a) - 1
	if t == '1':
		if S[a] == b:
			continue
		tmp_index = bisect_left(dic[S[a]], a)
		dic[S[a]].pop(tmp_index)
		insort_left(dic[b], a)
		S[a] = b
	elif t == '2':
		b = int(b) - 1
		cnt = 0
		for li in dic.values():
			if li and a <= li[-1] and (li[bisect_left(li, a)] <= b):
				cnt += 1
		print(cnt)


from bisect import bisect_left
import string
dic = {c: [] for c in string.ascii_lowercase}
N = int(input())
S = list(input())
Q = int(input())
for i in range(len(S)):
	dic[S[i]].append(i + 1)
for i in range(Q):
	(a, b, c) = map(str, input().split())
	if a == '1':
		if S[int(b) - 1] == c:
			continue
		b = int(b)
		f = S[b - 1]
		d = bisect_left(dic[f], b)
		e = bisect_left(dic[c], b)
		dic[f].pop(d)
		dic[c].insert(e, b)
		S[b - 1] = c
	else:
		ans = 0
		(b, c) = (int(b), int(c))
		for j in string.ascii_lowercase:
			d = bisect_left(dic[j], b)
			if d < len(dic[j]):
				if dic[j][d] <= c:
					ans += 1
		print(ans)


f = input
from bisect import bisect_left as g, insort as h
(n, s) = (int(f()), list(f()))
d = {chr(97 + i): [] for i in range(26)}
for i in range(n):
	d[s[i]] += [i]
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)


from collections import defaultdict

class BIT(object):

	def __init__(self, N, init=0):
		self.N = N
		self.bit = [init for _ in range(N)]

	def add(self, k, w):
		x = k
		while x < self.N:
			self.bit[x] += w
			x |= x + 1

	def sum(self, k):
		s = 0
		x = k - 1
		while x >= 0:
			s += self.bit[x]
			x = (x & x + 1) - 1
		return s
n = int(input())
s = list(input())
q = int(input())
d = defaultdict(lambda : BIT(n))
for (i, si) in enumerate(s):
	d[si].add(i, 1)
for i in range(q):
	(k, x, y) = input().split()
	if k == '1':
		x = int(x) - 1
		d[s[x]].add(x, -1)
		d[y].add(x, 1)
		s[x] = y
	else:
		l = int(x) - 1
		r = int(y) - 1
		ans = 0
		for v in d.values():
			ans += v.sum(r + 1) - v.sum(l) > 0
		print(ans)


import sys
sr = lambda : sys.stdin.readline().rstrip()
ir = lambda : int(sr())
lr = lambda : list(map(int, sr().split()))
from bisect import bisect_left

def resolve():
	N = ir()
	S = list(sr())
	a = [[] for _ in range(26)]
	for (i, s) in enumerate(S):
		a[ord(s) - ord('a')].append(i)
	Q = ir()
	for i in range(Q):
		(x, y, z) = sr().split()
		if x == '1':
			y = int(y) - 1
			if S[y] == z:
				continue
			u = ord(S[y]) - ord('a')
			l = bisect_left(a[u], y)
			a[u].pop(l)
			v = ord(z) - ord('a')
			l = bisect_left(a[v], y)
			a[v].insert(l, y)
			S[y] = z
		else:
			y = int(y) - 1
			z = int(z) - 1
			ans = 0
			for i in range(26):
				l = bisect_left(a[i], y)
				if l == len(a[i]):
					continue
				elif a[i][l] <= z:
					ans += 1
			print(ans)
resolve()


import bisect
from collections import defaultdict
N = int(input())
S = list(input())
Q = int(input())
alpha_dic = defaultdict(list)
for (i, s) in enumerate(S):
	alpha_dic[s].append(i)
for _ in range(Q):
	(l, m, n) = input().split()
	if l == '1':
		m = int(m) - 1
		c = S[m]
		if c == n:
			continue
		else:
			i = bisect.bisect_left(alpha_dic[c], m)
			del alpha_dic[c][i]
			bisect.insort_left(alpha_dic[n], m)
			S[m] = n
	else:
		(m, n) = (int(m) - 1, int(n) - 1)
		cnt = 0
		for (_, val) in list(alpha_dic.items()):
			if not val:
				continue
			left_idx = bisect.bisect_left(val, m)
			right_idx = bisect.bisect_left(val, n)
			l = len(val)
			if left_idx > right_idx or (left_idx == right_idx and left_idx == l) or (left_idx == right_idx and val[left_idx] != m and (val[right_idx] != n)):
				continue
			cnt += 1
		print(cnt)


N = int(input())
S = list(input())
Q = int(input())
query = [input().split() for _ in range(Q)]
bit = [[0 for _ in range(26)] for _ in range(N + 1)]

def bit_add(i, s, x):
	j = ord(s) - ord('a')
	while i <= N:
		bit[i][j] += x
		i += i & -i

def bit_sum(i):
	s = [0] * 26
	while i:
		for j in range(26):
			s[j] += bit[i][j]
		i -= i & -i
	return s
for i in range(1, N + 1):
	s = S[i - 1]
	bit_add(i, s, 1)
for (x, y, z) in query:
	if x == '1':
		y = int(y)
		bit_add(y, S[y - 1], -1)
		bit_add(y, z, 1)
		S[y - 1] = z
	if x == '2':
		answer = 0
		(y, z) = (int(y) - 1, int(z))
		sum_y = bit_sum(y)
		sum_z = bit_sum(z)
		for i in range(26):
			if sum_z[i] - sum_y[i] > 0:
				answer += 1
		print(answer)


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.size = n
		self.tree = [0] * (n + 1)

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

	def add(self, i, x):
		while i <= self.size:
			self.tree[i] += x
			i += i & -i
N = int(input())
S = list(input())
Q = int(input())
trees = [BIT(5 * 10 ** 5 + 2) for _ in range(26)]
for i in range(N):
	trees[ord(S[i]) - ord('a')].add(i + 1, 1)
for _ in range(Q):
	(s, *x) = input().split()
	if s == '1':
		i = int(x[0])
		c = x[1]
		trees[ord(S[i - 1]) - ord('a')].add(i, -1)
		trees[ord(c) - ord('a')].add(i, 1)
		S[i - 1] = c
	else:
		(l, r) = map(int, x)
		cnt = 0
		for i in range(26):
			cnt += int(trees[i].sum(r) - trees[i].sum(l - 1) > 0)
		print(cnt)


class SegmentTree:

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

	def cmpFunc(self, left, right):
		return left | right

	def build(self, rawData):
		self.data[self.size - 1:self.size - 1 + len(rawData)] = rawData
		for i in range(self.size - 1)[::-1]:
			self.data[i] = self.cmpFunc(self.data[2 * i + 1], self.data[2 * i + 2])

	def update(self, index, value):
		index += self.size - 1
		self.data[index] = value
		while index >= 0:
			index = (index - 1) // 2
			self.data[index] = self.cmpFunc(self.data[2 * index + 1], self.data[2 * index + 2])

	def query(self, left, right):
		L = left + self.size
		R = right + self.size
		ret = self.initValue
		while L < R:
			if R & 1:
				R -= 1
				ret = self.cmpFunc(ret, self.data[R - 1])
			if L & 1:
				ret = self.cmpFunc(ret, self.data[L - 1])
				L += 1
			L >>= 1
			R >>= 1
		return ret

def cToI(s):
	return ord(s) - ord('a')
N = int(input())
S = list(map(cToI, input()))
S = [1 << s for s in S]
tree = SegmentTree(N, 0)
tree.build(S)
Q = int(input())
ans = []
for _ in range(Q):
	(q1, q2, q3) = input().split()
	if q1 == '1':
		tree.update(int(q2) - 1, 1 << cToI(q3))
	else:
		ans.append(tree.query(int(q2) - 1, int(q3)))
for a in ans:
	cnt = 0
	while a > 0:
		cnt += a % 2
		a //= 2
	print(cnt)


import sys
sys.setrecursionlimit(10 ** 6)
input = sys.stdin.readline
N = int(input())
S = input().strip()
Q = int(input())
n = 1
while n < N:
	n *= 2
T = [0] * (2 * n)

def update(k, a):
	k += n - 1
	T[k] = 1 << ord(a) - 97
	while k > 0:
		k = (k - 1) // 2
		T[k] = T[k * 2 + 1] | T[k * 2 + 2]

def query(a, b, k, l, r):
	if r <= a or b <= l:
		return 0
	if a <= l and r <= b:
		return T[k]
	else:
		vl = query(a, b, k * 2 + 1, l, (l + r) // 2)
		vr = query(a, b, k * 2 + 2, (l + r) // 2, r)
		return vl | vr
for i in range(N):
	update(i, S[i])
for q in range(Q):
	(f, i, c) = [x for x in input().strip().split()]
	if f == '1':
		update(int(i) - 1, c)
	elif f == '2':
		tmp = query(int(i) - 1, int(c), 0, 0, n)
		ans = 0
		for i in range(26):
			ans += tmp >> i & 1
		print(ans)


import sys
import math
import collections
import bisect
import itertools
import fractions
import copy
import decimal
import queue
sys.setrecursionlimit(10000001)
INF = 10 ** 16
MOD = 10 ** 9 + 7
ni = lambda : int(sys.stdin.readline())
ns = lambda : list(map(int, sys.stdin.readline().split()))
na = lambda : list(map(int, sys.stdin.readline().split()))

def main():
	n = ni()
	s = list(input())
	q = ni()
	alphabet_idx = {}
	for i in range(26):
		alphabet_idx[i] = []
	for (i, si) in enumerate(s):
		alphabet_idx[ord(si) - ord('a')].append(i)
	for _ in range(q):
		(qi, a, b) = input().split()
		(qi, a) = (int(qi), int(a))
		if qi == 1:
			a -= 1
			if s[a] == b:
				continue
			del_char = ord(s[a]) - ord('a')
			del_idx = bisect.bisect_left(alphabet_idx[del_char], a)
			del alphabet_idx[del_char][del_idx]
			insert_char = ord(b) - ord('a')
			insert_idx = bisect.bisect_left(alphabet_idx[insert_char], a)
			alphabet_idx[insert_char].insert(insert_idx, a)
			s[a] = b
		if qi == 2:
			b = int(b)
			a -= 1
			b -= 1
			ans = 0
			for i in range(26):
				a_idx = bisect.bisect_left(alphabet_idx[i], a)
				if a_idx < len(alphabet_idx[i]):
					if alphabet_idx[i][a_idx] <= b:
						ans += 1
			print(ans)

def __starting_point():
	main()
__starting_point()


class SegTree:

	def __init__(self, N, S):
		self.N = 2 ** (N - 1).bit_length()
		self.tree = [0 for i in range(self.N * 2 - 1)]
		for i in range(len(S)):
			self.tree[self.N - 1 + i] = 1 << ord(S[i]) - ord('a')
		for i in range(self.N - 2, -1, -1):
			self.tree[i] = self.tree[i * 2 + 1] | self.tree[i * 2 + 2]

	def update(self, index, char):
		i = self.N - 1 + index
		self.tree[i] = 1 << ord(char) - ord('a')
		while i > 0:
			i = (i - 1) // 2
			self.tree[i] = self.tree[i * 2 + 1] | self.tree[i * 2 + 2]

	def get(self, a, b):
		return self.query(a, b, 0, 0, self.N)

	def query(self, a, b, k, l, r):
		if r <= a or b <= l:
			return 0
		elif a <= l and r <= b:
			return self.tree[k]
		else:
			left = self.query(a, b, 2 * k + 1, l, (l + r) // 2)
			right = self.query(a, b, 2 * k + 2, (l + r) // 2, r)
			return left | right

def solve():
	N = int(input())
	S = list(input().strip())
	tree = SegTree(N, S)
	Q = int(input())
	for _ in range(Q):
		(t_q, in_1, in_2) = input().split()
		if t_q == '1':
			i_q = int(in_1)
			c_q = in_2
			tree.update(i_q - 1, c_q)
		else:
			l_q = int(in_1)
			r_q = int(in_2)
			print(bin(tree.get(l_q - 1, r_q)).count('1'))
solve()


import sys
input = sys.stdin.readline

class BIT:

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

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

	def acc(self, i):
		s = 0
		while i > 0:
			s += self.bit[i]
			i -= i & -i
		return s
N = int(input())
S = list(input()[:-1])
bits = [BIT(N) for _ in range(26)]
for i in range(N):
	j = ord(S[i]) - ord('a')
	bits[j].add(i, 1)
Q = int(input())
for _ in range(Q):
	q = input().split()
	if q[0] == '1':
		(i, c) = (int(q[1]) - 1, q[2])
		j = ord(S[i]) - ord('a')
		bits[j].add(i, -1)
		k = ord(c) - ord('a')
		bits[k].add(i, 1)
		S[i] = c
	else:
		(l, r) = (int(q[1]) - 1, int(q[2]) - 1)
		ans = 0
		for i in range(26):
			if bits[i].acc(r + 1) - bits[i].acc(l) > 0:
				ans += 1
		print(ans)


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])


n = int(input())
s = input()
q = int(input())
Seg_Len = 1 << 19
seg = [0 for i in range(Seg_Len * 2)]

def add(ind, v):
	ind += Seg_Len - 1
	seg[ind] = v
	while 1:
		ind //= 2
		if ind == 0:
			break
		seg[ind] = seg[ind * 2] | seg[ind * 2 + 1]

def sum1(l, r):
	l += Seg_Len - 1
	r += Seg_Len - 1
	ans = 0
	while l < r:
		if l % 2 == 1:
			ans |= seg[l]
			l += 1
		l //= 2
		if r % 2 == 1:
			ans |= seg[r - 1]
			r -= 1
		r //= 2
	tmp = 0
	while ans:
		if ans & 1:
			tmp += 1
		ans >>= 1
	return tmp
alp = 'abcdefghijklmnopqrstuvwxyz'
d = {}
for i in range(len(alp)):
	d[alp[i]] = 2 ** i
for i in range(len(s)):
	add(i + 1, d[s[i]])
for i in range(q):
	(com, a, b) = input().split()
	if com == '1':
		ind = int(a)
		v = d[b]
		add(ind, v)
	if com == '2':
		l = int(a)
		r = int(b)
		print(sum1(l, r + 1))


def bitadd(a, w, bit):
	x = a
	while x <= len(bit) - 1:
		bit[x] += w
		x += x & -1 * x

def bitsum(a, bit):
	if a == 0:
		return 0
	ret = 0
	x = a
	while x > 0:
		ret += bit[x]
		x -= x & -1 * x
	return ret
alp = 'abcdefghijklmnopqrstuvwxyz'
al = {}
for i in range(26):
	al[alp[i]] = i
N = int(input())
BITS = [[0] * (N + 1) for i in range(26)]
S = list(input())
for i in range(N):
	bitadd(i + 1, 1, BITS[al[S[i]]])
Q = int(input())
for i in range(Q):
	(qs, x, y) = input().split()
	qs = int(qs)
	if qs == 1:
		x = int(x)
		bitadd(x, -1, BITS[al[S[x - 1]]])
		bitadd(x, 1, BITS[al[y]])
		S[x - 1] = y
	else:
		x = int(x)
		y = int(y)
		ans = 0
		for j in range(26):
			ans += min(1, bitsum(y, BITS[j]) - bitsum(x - 1, BITS[j]))
		print(ans)


from bisect import bisect_left
n = int(input())
s = list(input())
q = int(input())
query = [input() for _ in range(q)]
p = [[] for _ in range(26)]
for (i, x) in enumerate(s):
	p[ord(x) - ord('a')].append(i)
for x in query:
	(a, b, c) = x.split()
	if a == '1':
		b = int(b) - 1
		if s[b] == c:
			continue
		d = ord(s[b]) - ord('a')
		e = ord(c) - ord('a')
		temp = bisect_left(p[d], b)
		p[d].pop(temp)
		temp = bisect_left(p[e], b)
		p[e].insert(temp, b)
		s[b] = c
	else:
		b = int(b) - 1
		c = int(c) - 1
		ans = 0
		for i in range(26):
			L = bisect_left(p[i], b)
			if L >= len(p[i]):
				continue
			if p[i][L] <= c:
				ans += 1
		print(ans)


from bisect import bisect_left, bisect_right
import string
dic = {c: [] for c in string.ascii_lowercase}
n = int(input())
s = list(input())
q = int(input())
for (i, c) in enumerate(s, start=1):
	dic[c].append(i)
for i in range(q):
	(p, l, r) = map(str, input().split())
	if p == '1':
		j = int(l)
		if r == s[j - 1]:
			continue
		c = s[j - 1]
		dic[c].pop(bisect_left(dic[c], j))
		dic[r].insert(bisect_left(dic[r], j), j)
		s[j - 1] = r
	else:
		ans = 0
		l = int(l)
		r = int(r)
		for c in string.ascii_lowercase:
			pl = bisect_left(dic[c], l)
			if pl < len(dic[c]):
				if dic[c][pl] <= r:
					ans += 1
		print(ans)


import sys
import bisect
n = int(sys.stdin.readline().strip())
s = list(sys.stdin.readline().strip())
alpha = 'abcdefghijklmnopqrstuvwxyz'
dict = {i: [] for i in alpha}
for (i, _s) in enumerate(s):
	dict[_s].append(i)
q = int(sys.stdin.readline().strip())
for i in range(q):
	(type, first, last) = [i for i in sys.stdin.readline().split()]
	if type == '2':
		first = int(first)
		last = int(last)
		first -= 1
		last -= 1
		cnt = 0
		for ls in dict.values():
			if bisect.bisect_left(ls, first) != bisect.bisect_right(ls, last):
				cnt += 1
		print(cnt)
	else:
		first = int(first)
		first -= 1
		_s = s[first]
		if _s == last:
			continue
		del dict[_s][bisect.bisect_left(dict[_s], first)]
		s[first] = last
		bisect.insort_left(dict[last], first)


def main():
	import bisect
	n = int(input())
	s = list(input())
	q = int(input())
	d = {}
	for i in range(26):
		d[chr(ord('a') + i)] = []
	for i in range(n):
		d[s[i]].append(i)
	for i in range(q):
		(t, a, b) = input().split()
		if t == '1':
			a = int(a) - 1
			if s[a] == b:
				continue
			idx = bisect.bisect_left(d[s[a]], a)
			d[s[a]].pop(idx)
			bisect.insort_left(d[b], a)
			s[a] = b
		else:
			a = int(a) - 1
			b = int(b) - 1
			c = 0
			for i in range(26):
				idx = bisect.bisect_left(d[chr(ord('a') + i)], a)
				if idx < len(d[chr(ord('a') + i)]) and d[chr(ord('a') + i)][idx] <= b:
					c += 1
			print(c)
main()


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()


n = int(input())
S = input()
s = []
for i in range(n):
	s.append(S[i])
q = int(input())
BIT = []
for i in range(26):
	B = [0] * (n + 1)
	BIT.append(B)

def sum_of_1_to_i(i, LIST):
	z = 0
	while i > 0:
		z += LIST[i]
		i -= i & -i
	return z

def update(i, j, LIST):
	while i <= n:
		LIST[i] += j
		i += i & -i
for i in range(n):
	k = ord(s[i]) - 97
	update(i + 1, 1, BIT[k])
ans = []
for i in range(q):
	(a, b, c) = input().split()
	a = int(a)
	b = int(b)
	if a == 1:
		temp = s[b - 1]
		if temp == c:
			None
		else:
			update(b, -1, BIT[ord(temp) - 97])
			update(b, 1, BIT[ord(c) - 97])
			s[b - 1] = c
	else:
		c = int(c)
		cur = 0
		for j in range(26):
			if sum_of_1_to_i(c, BIT[j]) - sum_of_1_to_i(b - 1, BIT[j]) != 0:
				cur += 1
		ans.append(cur)
for i in range(len(ans)):
	print(ans[i])


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'))


def main():
	n = int(input())
	a = ord('a')
	orda = lambda x: ord(x) - a
	s = list(map(orda, list(input())))
	q = int(input())
	bits = [BIT(n) for _ in range(26)]
	for (i, si) in enumerate(s, 1):
		bits[si].add(i, 1)
	for _ in range(q):
		(t, i, c) = input().split()
		i = int(i)
		if t == '1':
			bits[s[i - 1]].add(i, -1)
			bits[ord(c) - a].add(i, 1)
			s[i - 1] = ord(c) - a
		else:
			c = int(c)
			cnt = 0
			for bit in bits:
				is_in = bit.sum_(c) - bit.sum_(i - 1)
				if is_in:
					cnt += 1
			print(cnt)

class BIT:
	__slots__ = ['length', 'data']

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

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

	def sum_(self, i):
		x = 0
		while i > 0:
			x += self.data[i]
			i -= i & -i
		return x
main()


class BIT:

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

	def add(self, i, value):
		i = i + 1
		while i <= self.n:
			self.bit[i] += value
			i += i & -i

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

	def sum(self, l, r):
		return self._sum(r) - self._sum(l)
n = int(input())
S = input()
q = int(input())
Query = [input().split() for _ in range(q)]
bits = [BIT(n) for i in range(26)]
s = []
for (i, c) in enumerate(S):
	bits[ord(c) - ord('a')].add(i, 1)
	s.append(c)
for (q_type, fr, to) in Query:
	if q_type == '1':
		i = int(fr) - 1
		bits[ord(s[i]) - ord('a')].add(i, -1)
		bits[ord(to) - ord('a')].add(i, 1)
		s[i] = to
	else:
		(l, r) = (int(fr) - 1, int(to))
		tmp = 0
		for i in range(26):
			if bits[i].sum(l, r):
				tmp += 1
		print(tmp)


from bisect import insort_left, bisect_left
n = int(input())
s = list(input())
Q = int(input())
query = [input() for _ in range(Q)]
dic = {chr(i + ord('a')): [] for i in range(26)}
for (ind, c) in enumerate(s):
	dic[c].append(ind)
for q in query:
	(t, a, b) = q.split()
	a = int(a) - 1
	if t == '1':
		if s[a] == b:
			continue
		ind = bisect_left(dic[s[a]], a)
		dic[s[a]].pop(ind)
		insort_left(dic[b], a)
		s[a] = b
	else:
		b = int(b) - 1
		tmp = 0
		for li in dic.values():
			if li and a <= li[-1] and (li[bisect_left(li, a)] <= b):
				tmp += 1
		print(tmp)


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)


from bisect import bisect_left, insort_left
import sys
input = sys.stdin.readline
OFS = ord('a')
_ = input()
S = list(input()[:-1])
D = [[] for _ in [0] * 26]
for (i, s) in enumerate(S):
	D[ord(s) - OFS].append(i)
for _ in [0] * int(input()):
	Q = input()[:-1].split()
	if Q[0] == '1':
		(i, c) = (int(Q[1]) - 1, Q[2])
		if S[i] != c:
			s = ord(S[i]) - OFS
			D[s].pop(bisect_left(D[s], i))
			insort_left(D[ord(c) - OFS], i)
			S[i] = c
	else:
		(l, r) = (int(Q[1]) - 1, int(Q[2]) - 1)
		cnt = 0
		for L in D:
			i = bisect_left(L, l)
			if i < len(L) and L[i] <= r:
				cnt += 1
		print(cnt)


from bisect import bisect_left, bisect_right
n = int(input())
s = list(input())
q = int(input())
al = 'abcdefghijklmnopqrstuvwxyz'
dicq = {i: [] for i in al}
for (i, si) in enumerate(s):
	dicq[si].append(i)

def q1(iq, cq):
	dicq[s[iq]].pop(bisect_left(dicq[s[iq]], iq))
	s[iq] = cq
	dicq[cq].insert(bisect_left(dicq[cq], iq), iq)

def q2(l, r):
	ret = 0
	for ai in al:
		if len(dicq[ai]) == 0:
			continue
		li = bisect_left(dicq[ai], l)
		ri = bisect_right(dicq[ai], r)
		if li != ri:
			ret += 1
		elif li == len(dicq[ai]):
			continue
		elif dicq[ai][li] == l:
			ret += 1
	print(ret)
for i in range(q):
	(fg, x, y) = input().split()
	if fg == '1':
		q1(int(x) - 1, y)
	else:
		q2(int(x) - 1, int(y) - 1)


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)


def main():
	import sys
	b = sys.stdin.buffer
	input = b.readline
	n = int(input())
	d = [set() for _ in range(n)] + [{c} for c in input()]
	for i in range(n - 1, 0, -1):
		d[i] = d[i + i] | d[i - ~i]
	r = []
	add = r.append
	input()
	for (q, a, b) in zip(*[iter(b.read().split())] * 3):
		i = int(a) + n - 1
		if q < b'2':
			d[i] = {b[0]}
			while i:
				i >>= 1
				d[i] = d[i + i] | d[i - ~i]
			continue
		j = int(b) + n
		s = set()
		while i < j:
			if i & 1:
				s |= d[i]
				i += 1
			if j & 1:
				j -= 1
				s |= d[j]
			i >>= 1
			j >>= 1
		add(len(s))
	print(' '.join(map(str, r)))
main()


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])


N = int(input())
from functools import reduce
size = int(N ** 0.5 + (1 - 1e-09))
a = [0] * N
b = [0] * size
f = lambda v: reduce(lambda x, y: x | y, v, 0)

def init(v):
	a = v
	b = [f(a[j * size:(j + 1) * size]) for j in range(size)]
	return (a, b)

def update(i, v):
	a[i] = v
	j = i // size
	b[j] = f(a[j * size:(j + 1) * size])

def r_query(l, r):
	(L, R) = (0 - -l // size, r // size)
	if L >= R:
		return f(a[l:r])
	else:
		return f(a[l:L * size] + b[L:R] + a[R * size:r])

def c(n):
	r = 0
	while n:
		r += n & 1
		n >>= 1
	return r
o = lambda c: ord(c) - ord('a')
bit = [2 ** i for i in range(26)]
S = input()
Q = int(input())
XYZ = [input().split() for i in range(Q)]
(a, b) = init([bit[o(c)] for c in S])
for (x, y, z) in XYZ:
	if x == '1':
		update(int(y) - 1, bit[o(z)])
	else:
		print(c(r_query(int(y) - 1, int(z))))


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()


N = int(input())

def idx(s):
	return ord(s) - 97

class BIT:

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

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

	def add(self, i, x):
		i += 1
		while i <= self.size:
			self.tree[i] += x
			i += i & -i
d = {}
for i in range(26):
	d[i] = BIT(N)
S = input()
for i in range(N):
	d[idx(S[i])].add(i, 1)
S = list(S)
Q = int(input())
for _ in range(Q):
	q = input().split()
	if q[0] == '1':
		i = int(q[1]) - 1
		s = S[i]
		d[idx(s)].add(i, -1)
		S[i] = q[2]
		d[idx(q[2])].add(i, 1)
	else:
		(l, r) = (int(q[1]) - 1, int(q[2]) - 1)
		res = 0
		for i in range(26):
			c = d[i].sum(r)
			if l != 0:
				c -= d[i].sum(l - 1)
			c = min(1, c)
			res += c
		print(res)


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)


from collections import defaultdict
import bisect
alphabet = 'abcdefghijklmnopqrstuvwxyz'
bS = int(input())
S = input()
nQ = int(input())
S = [i for i in S]
query = []
for i in range(nQ):
	query.append(input().split())
locs = defaultdict(list)
for (i, char) in enumerate(S):
	locs[char].append(i)

def countChars(iter, ss, ee):
	nChar = 0
	for i in alphabet:
		if len(locs[i]) == 0:
			pass
		else:
			sptr = bisect.bisect_right(locs[i], ss)
			eptr = bisect.bisect_left(locs[i], ee)
			if sptr == eptr:
				if sptr < 1 or sptr > len(locs[i]):
					continue
				elif locs[i][sptr - 1] == ss:
					nChar += 1
			else:
				nChar += 1
	return nChar
res = []
for (iter, iQ) in enumerate(query):
	if int(iQ[0]) == 2:
		res.append(str(countChars(iter, int(iQ[1]) - 1, int(iQ[2]))))
	if int(iQ[0]) == 1:
		location = int(iQ[1]) - 1
		curChar = S[location]
		if curChar != iQ[2]:
			locs[curChar].remove(location)
			bisect.insort(locs[iQ[2]], location)
			S[location] = iQ[2]
print(' '.join(res))


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)


N = int(input())
S = [x for x in input()]
Q = int(input())
BIT = [[0] * (N + 1) for _ in range(26)]

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

def BIT_update(input_BIT, idx, x):
	while idx <= N:
		input_BIT[idx] += x
		idx += idx & -idx
	return
for (i, c) in enumerate(S):
	BIT_update(BIT[ord(c) - ord('a')], i + 1, 1)
for _ in range(Q):
	(a, b, c) = input().rstrip().split()
	if int(a) == 1:
		BIT_update(BIT[ord(S[int(b) - 1]) - ord('a')], int(b), -1)
		BIT_update(BIT[ord(c) - ord('a')], int(b), 1)
		S[int(b) - 1] = c
	else:
		count = 0
		for i in range(26):
			if BIT_query(BIT[i], int(b) - 1) != BIT_query(BIT[i], int(c)):
				count += 1
		print(count)


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)


import sys
sysread = sys.stdin.readline
from collections import defaultdict
sys.setrecursionlimit(10 ** 7)
import math

class SegTree:

	def __init__(self, n, init_val=0):
		self.n = n
		self.init_val = init_val
		self.n_leaf = 2 ** math.ceil(math.log2(n))
		self.bins = [init_val] * (self.n_leaf * 2)

	def val_append(self, A):
		if len(A) != self.n:
			raise ValueError('The number of input should be same with n_leaf')
		for (i, a) in enumerate(A):
			self.bins[self.n_leaf + i] = a
		self._calc()
		return None

	def _calc(self):
		i = self.n_leaf - 1
		while i > 0:
			self.bins[i] = self._criteria(self.bins[i * 2], self.bins[i * 2 + 1])
			i -= 1
		return None

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

	def eval_between(self, x, y):
		(l, r) = (x + self.n_leaf - 1, y + self.n_leaf - 1)
		ret = self._criteria(self.bins[l], self.bins[r])
		while l < r:
			if l % 2 == 1:
				ret = self._criteria(self.bins[l], ret)
				l += 1
				continue
			if r % 2 == 0:
				ret = self._criteria(self.bins[r], ret)
				r -= 1
				continue
			l = l // 2
			r = r // 2
			ret = self._criteria(self.bins[l], ret)
			ret = self._criteria(self.bins[r], ret)
		return ret

	def update(self, node, pro):
		current = node + self.n_leaf - 1
		self.bins[current] = pro
		current //= 2
		while current > 0:
			self.bins[current] = self._criteria(self.bins[current * 2 + 1], self.bins[current * 2])
			current //= 2
		return None

def run():
	N = int(input())
	S = list(input())
	Q = int(input())
	queries = [sysread().split() for _ in range(Q)]
	bins = [0] * N
	for (i, s) in enumerate(S):
		id = ord(s) - 97
		bins[i] = 1 << id
	segtree = SegTree(N)
	segtree.val_append(bins)
	for (type, i, c) in queries:
		if type == '1':
			c = 1 << ord(c) - 97
			segtree.update(int(i), c)
		else:
			(i, c) = (int(i), int(c))
			tmp = segtree.eval_between(i, c)
			print(bin(tmp).count('1'))

def __starting_point():
	run()
__starting_point()


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)


class BIT:

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

	def total(self, i):
		res = 0
		while i:
			res += self.data[i]
			i -= i & -i
		return res

	def add(self, i, val):
		while i <= self.n:
			self.data[i] += val
			i += i & -i
N = int(input())
bit = BIT(N)
for (i, c) in enumerate(input()):
	ind = ord(c) - ord('a')
	bit.add(i + 1, 1 << ind * 20)
Q = int(input())
for _ in range(Q):
	parts = input().split()
	if parts[0] == '1':
		ind = int(parts[1])
		nval = 1 << (ord(parts[2]) - ord('a')) * 20
		val = bit.total(ind) - bit.total(ind - 1)
		bit.add(ind, nval - val)
	else:
		(l, r) = map(int, parts[1:])
		val = bit.total(r) - bit.total(l - 1)
		mask = (1 << 20) - 1
		ans = 0
		while val:
			if val & mask:
				ans += 1
			val >>= 20
		print(ans)


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)


n = int(input())
S = list(input())
q = int(input())
D = [[0] * 26 for _ in range(n + 1)]
for (i, s) in enumerate(S):
	for j in range(26):
		if j == ord(s) - 97:
			D[i + 1][j] = D[i][j] + 1
		else:
			D[i + 1][j] = D[i][j]
n_max = n + 1
nn = n_max.bit_length() + 1
BITS = [[0] * 2 ** nn for _ in range(26)]
for i in range(26):
	BITS[i].insert(0, 0)

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

def bitadd(BIT, i, x):
	while i <= 2 ** nn:
		BIT[i] += x
		i += i & -i
	return BIT
for _ in range(q):
	(q1, q2, q3) = map(str, input().split())
	if q1 == '1':
		num = int(q2) - 1
		prev = ord(S[num]) - 97
		new = ord(q3) - 97
		S[num] = q3
		if prev != new:
			bitadd(BITS[prev], num + 1, -1)
			bitadd(BITS[new], num + 1, 1)
	else:
		(l, r) = (int(q2), int(q3))
		ans = 0
		for i in range(26):
			diff = D[r][i] - D[l - 1][i] + bitsum(BITS[i], r) - bitsum(BITS[i], l - 1)
			if diff > 0:
				ans += 1
		print(ans)


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()


import sys
from bisect import bisect_left, bisect_right, insort_left
from collections import defaultdict
sr = lambda : sys.stdin.readline().rstrip()
ir = lambda : int(sr())
lr = lambda : list(map(int, sr().split()))
N = ir()
S = list(sr())
dic = defaultdict(list)
for (i, s) in enumerate(S):
	dic[s].append(i)
Q = ir()
for _ in range(Q):
	(a, b, c) = sr().split()
	if a == '1':
		b = int(b) - 1
		if S[b] == c:
			continue
		dic[S[b]].remove(b)
		insort_left(dic[c], b)
		S[b] = c
	else:
		b = int(b) - 1
		c = int(c) - 1
		kind = 0
		for x in range(26):
			word = chr(ord('a') + x)
			if len(dic[word]) == 0:
				continue
			i = bisect_left(dic[word], b)
			j = bisect_right(dic[word], c)
			if i != j:
				kind += 1
		print(kind)


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()


N = int(input())
S = input()
seg = [0] * (2 * N - 1)

def update(k, x):
	k += N - 1
	seg[k] = 2 ** x
	while k:
		k = (k - 1) // 2
		seg[k] = seg[2 * k + 1] | seg[2 * k + 2]

def query(p, q):
	p += N - 1
	q += N - 2
	res = 0
	while q - p > 1:
		if p & 1 == 0:
			res = res | seg[p]
		if q & 1 == 1:
			res = res | seg[q]
			q -= 1
		p //= 2
		q = (q - 1) // 2
	if p == q:
		res |= seg[q]
	else:
		res |= seg[p] | seg[q]
	return bin(res).count('1')

def f(s):
	return ord(s) - ord('a') + 1
for i in range(N):
	update(i, f(S[i]))
Q = int(input())
for _ in range(Q):
	(a, b, c) = map(str, input().split())
	if a == '1':
		update(int(b) - 1, f(c))
	else:
		print(query(int(b) - 1, int(c)))


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'))


def main():
	n = int(input().strip())
	s = list(input().strip())
	bit = [[0] * 26 for _ in range(n + 1)]

	def query(i):
		result = [0] * 26
		while i:
			for (j, x) in enumerate(bit[i]):
				result[j] += x
			i -= i & -i
		return result

	def update(i, c, val):
		j = ord(c) - ord('a')
		while i < len(bit):
			bit[i][j] += val
			i += i & -i
	for (i, c) in enumerate(s, 1):
		update(i, c, 1)
	q = int(input().strip())
	for _ in range(q):
		Q = input().strip().split()
		if Q[0] == '1':
			(i, c) = (int(Q[1]), Q[2])
			update(i, s[i - 1], -1)
			update(i, c, 1)
			s[i - 1] = c
		else:
			(l, r) = (int(Q[1]), int(Q[2]))
			cnt = [x - y for (x, y) in zip(query(r), query(l - 1))]
			print(sum((x > 0 for x in cnt)))
main()


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 operator import or_

class SegmentTree:
	_f = None
	_data = None
	_offset = None
	_size = None

	def __init__(self, size, f):
		self._f = f
		self._size = size
		t = 1
		while t < size:
			t *= 2
		self._offset = t - 1
		self._data = [0] * (t * 2 - 1)

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

	def update(self, index, value):
		f = self._f
		data = self._data
		i = self._offset + index
		data[i] = value
		while i >= 1:
			i = (i - 1) // 2
			data[i] = f(data[i * 2 + 1], data[i * 2 + 2])

	def query(self, start, stop):

		def iter_segments(data, l, r):
			while l < r:
				if l & 1 == 0:
					yield data[l]
				if r & 1 == 0:
					yield data[r - 1]
				l = l // 2
				r = (r - 1) // 2
		f = self._f
		it = iter_segments(self._data, start + self._offset, stop + self._offset)
		result = next(it)
		for e in it:
			result = f(result, e)
		return result

def conv(c):
	return 1 << ord(c) - ord('a')
N = int(input())
S = input()
st = SegmentTree(N, or_)
st.build((conv(c) for c in S))
Q = int(input())
for _ in range(Q):
	q = input().split()
	if q[0] == '1':
		(i, c) = q[1:]
		i = int(i) - 1
		st.update(i, conv(c))
	elif q[0] == '2':
		(l, r) = list(map(int, q[1:]))
		print(bin(st.query(l - 1, r)).count('1'))


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)))


n = int(input())
s = [*input()]
q = int(input())
from collections import *
d = defaultdict(list)
from bisect import *
for (i, c) in enumerate(s):
	d[c] += [i]
for _ in range(q):
	(x, y, z) = input().split()
	y = int(y) - 1
	if x == '1':
		if s[y] == z:
			continue
		d[s[y]].pop(bisect(d[s[y]], y) - 1)
		s[y] = z
		insort(d[z], y)
	else:
		a = 0
		for l in d.values():
			if bisect(l, int(z) - 1) - bisect_left(l, y):
				a += 1
		print(a)


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)


import sys
from bisect import bisect, insort_left
iim = lambda : map(int, input().rstrip().split())

def resolve():
	N = int(input())
	S = list(input())
	Q = int(input())
	c0 = ord('a')
	S1 = [[] for i in range(26)]
	for (i, c1) in enumerate(S):
		ci = ord(c1) - c0
		S1[ci].append(i)
	ans = []
	for (cmd, i, j) in (line.split() for line in sys.stdin):
		i = int(i) - 1
		if cmd == '1':
			if S[i] == j:
				continue
			c1 = ord(S[i]) - c0
			s1 = S1[c1]
			s1.pop(bisect(s1, i) - 1)
			S[i] = j
			c1 = ord(j) - c0
			insort_left(S1[c1], i)
		elif cmd == '2':
			j = int(j) - 1
			num = 0
			for s1 in S1:
				ls = len(s1)
				k = bisect(s1, i - 1, 0, ls)
				if k == ls:
					continue
				if i <= s1[k] <= j:
					num += 1
			ans.append(num)
	print(*ans, sep='\n')
resolve()


N = int(input())
A = [ord(a) - 97 for a in input()]
NN = 19
BIT = [[0] * (2 ** NN + 1) for _ in range(26)]

def addbit(t, i, x):
	while i <= 2 ** NN:
		BIT[t][i] += x
		i += i & -i

def getsum(t, i):
	ret = 0
	while i != 0:
		ret += BIT[t][i]
		i -= i & -i
	return ret
for (i, a) in enumerate(A):
	addbit(a, i + 2, 1)
Q = int(input())
for _ in range(Q):
	(a, b, c) = input().rstrip().split()
	if a == '1':
		b = int(b)
		c = ord(c) - 97
		t = A[b - 1]
		addbit(t, b + 1, -1)
		addbit(c, b + 1, 1)
		A[b - 1] = c
	else:
		(b, c) = (int(b), int(c))
		s = 0
		for t in range(26):
			s += 1 if getsum(t, c + 1) - getsum(t, b) else 0
		print(s)


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()


import sys
read = sys.stdin.readline

def read_a_int():
	return int(read())

class SegmentTree:

	def __init__(self, ls: list, segfunc, identity_element):
		self.ide = identity_element
		self.func = segfunc
		n = len(ls)
		self.num = 2 ** (n - 1).bit_length()
		self.tree = [self.ide] * (2 * self.num - 1)
		for (i, l) in enumerate(ls):
			self.tree[i + self.num - 1] = l
		for i in range(self.num - 2, -1, -1):
			self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

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

	def query(self, l, r):
		if r <= l:
			return ValueError('invalid index (l,rがありえないよ)')
		l += self.num
		r += self.num
		res = self.ide
		while l < r:
			if l & 1:
				res = self.func(res, self.tree[l - 1])
				l += 1
			if r & 1:
				r -= 1
				res = self.func(res, self.tree[r - 1])
			l >>= 1
			r >>= 1
		return res

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

def moji_to_bit(a):
	return 1 << ord(a) - ord('a')

def bit_to_sum(n):
	return sum([n >> i & 1 for i in range(n.bit_length())])
N = read_a_int()
S = read()[:-1]
S_bit = [moji_to_bit(s) for s in S]
st = SegmentTree(S_bit, segfunc, 0)
Q = read_a_int()
for q in range(Q):
	(com, a, b) = read().split()
	if int(com) == 1:
		(i, c) = (int(a) - 1, b)
		st.update(i, moji_to_bit(c))
	else:
		(l, r) = (int(a) - 1, int(b))
		print(bit_to_sum(st.query(l, r)))


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)


N = int(input())
S = list(input())
Q = int(input())

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
en2asc = lambda s: ord(s) - 97
Bits = [Bit(N) for _ in range(26)]
for (i, s) in enumerate(S):
	Bits[en2asc(s)].add(i + 1, 1)
for _ in range(Q):
	q = input().split()
	if q[0] == '1':
		(i, c) = (int(q[1]), q[2])
		old = S[i - 1]
		Bits[en2asc(old)].add(i, -1)
		Bits[en2asc(c)].add(i, 1)
		S[i - 1] = c
	else:
		(l, r) = (int(q[1]), int(q[2]))
		ans = 0
		for b in Bits:
			ans += bool(b.sum(r) - b.sum(l - 1))
		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)


(n, s, _, *t) = open(0).read().split()
n = int(n)
d = [0] * n + [1 << ord(c) - 97 for c in s]
for i in range(n - 1, 0, -1):
	d[i] = d[i + i] | d[i - ~i]
for (q, a, b) in zip(*[iter(t)] * 3):
	(i, s) = (int(a) + n - 1, 0)
	if '2' > q:
		d[i] = 1 << ord(b) - 97
		while i > 1:
			i //= 2
			d[i] = d[i + i] | d[i - ~i]
		continue
	j = int(b) + n
	while i < j:
		if i & 1:
			s |= d[i]
			i += 1
		if j & 1:
			j -= 1
			s |= d[j]
		i //= 2
		j //= 2
	print(bin(s).count('1'))


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 collections import defaultdict
from bisect import bisect, insort, bisect_left
n = int(input())
s = list(input())
q = int(input())
d = defaultdict(list)
for i in range(n):
	d[s[i]] += [i]
for _ in range(q):
	(t, i, c) = input().split()
	(t, i) = (int(t), int(i) - 1)
	if t == 1:
		if s[i] == c:
			continue
		d[s[i]].pop(bisect(d[s[i]], i) - 1)
		s[i] = c
		insort(d[c], i)
	else:
		res = 0
		c = int(c) - 1
		for j in d.values():
			if bisect(j, c) - bisect_left(j, i):
				res += 1
		print(res)


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)


import sys
input = sys.stdin.readline
N = int(input())
S = list(input().strip())
Q = int(input())
LEN = N
BIT = [[0] * (LEN + 1) for i in range(26)]

def update(v, w, i):
	while v <= LEN:
		BIT[i][v] += w
		v += v & -v

def getvalue(v, i):
	ANS = 0
	while v != 0:
		ANS += BIT[i][v]
		v -= v & -v
	return ANS
for i in range(N):
	update(i + 1, 1, ord(S[i]) - 97)
for i in range(Q):
	(qf, x, y) = input().split()
	qf = int(qf)
	if int(qf) == 1:
		x = int(x)
		update(x, -1, ord(S[x - 1]) - 97)
		update(x, 1, ord(y) - 97)
		S[x - 1] = y
	else:
		x = int(x)
		y = int(y)
		ANS = 0
		for i in range(26):
			if getvalue(y, i) - getvalue(x - 1, i) > 0:
				ANS += 1
		print(ANS)


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'))


n = int(input())
l = list(input())
q = int(input())
bit = [[0] * (n + 1) for i in range(26)]

def bit_sum(o, i):
	s = 0
	while i:
		s += bit[o][i]
		i -= i & -i
	return s

def bit_add(o, i, x):
	while i <= n:
		bit[o][i] += x
		i += i & -i
for i in range(n):
	bit_add(ord(l[i]) - 97, i + 1, 1)
for i in range(q):
	(a, b, c) = input().split()
	b = int(b) - 1
	if a == '1':
		bit_add(ord(l[b]) - 97, b + 1, -1)
		l[b] = c
		bit_add(ord(c) - 97, b + 1, 1)
	else:
		c = int(c)
		print(sum((1 for o in range(26) if bit_sum(o, c) - bit_sum(o, b))))


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
n = int(input())
BIT = [[0] * n for i in range(26)]
w = [ord(x) - ord('a') for x in input()]
for i in range(n):
	k = i + 1
	while k <= n:
		BIT[w[i]][k - 1] += 1
		k = k + (k & -k)
q = int(input())
for i in range(q):
	(a, b, c) = input().split()
	if a == '1':
		k = int(b)
		while k <= n:
			BIT[ord(c) - ord('a')][k - 1] += 1
			k = k + (k & -k)
		k = int(b)
		while k <= n:
			BIT[w[int(b) - 1]][k - 1] -= 1
			k = k + (k & -k)
		w[int(b) - 1] = ord(c) - ord('a')
	else:
		b = int(b)
		c = int(c)
		ans = 0
		for i in range(26):
			cnt = 0
			k = c
			while k != 0:
				cnt += BIT[i][k - 1]
				k = k - (k & -k)
			k = b - 1
			while k != 0:
				cnt -= BIT[i][k - 1]
				k = k - (k & -k)
			if cnt > 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()