You are given a string $s$ consisting of lowercase Latin letters and $q$ queries for this string.

Recall that the substring $s[l; r]$ of the string $s$ is the string $s_l s_{l + 1} \dots s_r$. For example, the substrings of "codeforces" are "code", "force", "f", "for", but not "coder" and "top".

There are two types of queries:   $1~ pos~ c$ ($1 \le pos \le |s|$, $c$ is lowercase Latin letter): replace $s_{pos}$ with $c$ (set $s_{pos} := c$);  $2~ l~ r$ ($1 \le l \le r \le |s|$): calculate the number of distinct characters in the substring $s[l; r]$. 


-----Input-----

The first line of the input contains one string $s$ consisting of no more than $10^5$ lowercase Latin letters.

The second line of the input contains one integer $q$ ($1 \le q \le 10^5$) — the number of queries.

The next $q$ lines contain queries, one per line. Each query is given in the format described in the problem statement. It is guaranteed that there is at least one query of the second type.


-----Output-----

For each query of the second type print the answer for it — the number of distinct characters in the required substring in this query.


-----Examples-----
Input
abacaba
5
2 1 4
1 4 b
1 5 b
2 4 6
2 1 7

Output
3
1
2

Input
dfcbbcfeeedbaea
15
1 6 e
1 4 b
2 6 14
1 7 b
1 12 c
2 6 8
2 1 6
1 7 c
1 2 f
1 10 a
2 7 9
1 10 a
1 14 b
1 1 f
2 1 11

Output
5
2
5
2
6

Difficulty: MEDIUM_HARD
Tags: Data structures
Skill types: Data structures

Starter code:

Solutions:
import os
from io import BytesIO
input = BytesIO(os.read(0, os.fstat(0).st_size)).readline

def update(arr, index, value):
	while index <= len(arr) - 1:
		arr[index] += value
		index += index & -index

def sum(arr, index):
	result = 0
	while index > 0:
		result += arr[index]
		index -= index & -index
	return result

def init(fenwick, char, items):
	if char not in fenwick:
		fenwick[char] = [0] * (items + 1)

def main():
	s = list(input().strip())
	fenwick = {}
	for (index, char) in enumerate(s):
		init(fenwick, char, len(s))
		update(fenwick[char], index + 1, 1)
	q = int(input())
	while q:
		q -= 1
		(a, b, c) = input().split()
		a = int(a)
		b = int(b)
		if a == 2:
			c = int(c)
			count = 0
			for tree in fenwick.values():
				if sum(tree, c) - sum(tree, b - 1) > 0:
					count += 1
			print(count)
		else:
			c = ord(c)
			init(fenwick, s[b - 1], len(s))
			init(fenwick, c, len(s))
			update(fenwick[s[b - 1]], b, -1)
			update(fenwick[c], b, 1)
			s[b - 1] = c
main()


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)
(S, Q) = (list(ns()), ni())
N = len(S)
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
sys.setrecursionlimit(10 ** 9)
input = sys.stdin.readline

class SegmentTree:

	def __init__(self, n):
		self.n = 2 ** (n - 1).bit_length()
		self.data = [0 for _ in range(2 * self.n)]

	def set(self, k, v):
		v_val = ord(v) - ord('a')
		self.data[k + self.n - 1] = 1 << v_val

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

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

	def query(self, l, r):
		L = l + self.n
		R = r + self.n
		ret = 0
		while L < R:
			if R & 1:
				R -= 1
				ret |= self.data[R - 1]
			if L & 1:
				ret |= self.data[L - 1]
				L += 1
			L >>= 1
			R >>= 1
		return ret
S = [v for v in input()[:-1]]
N = len(S)
Q = int(input())
query = [[v for v in input()[:-1].split()] for _ in range(Q)]
Seg = SegmentTree(N)
for (i, s) in enumerate(S):
	Seg.set(i, s)
Seg.build()
for (q, v1, v2) in query:
	if q == '1':
		Seg.update(int(v1) - 1, v2)
	else:
		val = Seg.query(int(v1) - 1, int(v2))
		print(bin(val)[2:].count('1'))


import heapq
import math
import sys
input = sys.stdin.readline

def li():
	return [int(i) for i in input().rstrip('\n').split()]

def value():
	return int(input())

def givesum(a, b):
	c = [0] * 26
	for i in range(len(a)):
		c[i] = a[i] + b[i]
	return c

def dolist(a):
	c = [0] * 26
	c[ord(a) - ord('a')] = 1
	return c

class Node:

	def __init__(self, s, e):
		self.start = s
		self.end = e
		self.lis = [0] * 26
		self.left = None
		self.right = None

def build(nums, l, r):
	if l == r:
		temp = Node(l, l)
		temp.lis[ord(nums[l]) - ord('a')] = 1
	else:
		mid = l + r >> 1
		temp = Node(l, r)
		temp.left = build(nums, l, mid)
		temp.right = build(nums, mid + 1, r)
		temp.lis = givesum(temp.left.lis, temp.right.lis)
	return temp

def update(root, start, value):
	if root.start == root.end == start:
		root.lis = dolist(value)
	elif root.start <= start and root.end >= start:
		mid = root.start + root.end >> 1
		root.left = update(root.left, start, value)
		root.right = update(root.right, start, value)
		root.lis = givesum(root.left.lis, root.right.lis)
	return root

def query(root, start, end):
	if root.start >= start and root.end <= end:
		return root.lis
	elif root.start > end or root.end < start:
		return [0] * 26
	else:
		mid = start + end >> 1
		return givesum(query(root.left, start, end), query(root.right, start, end))
s = input().rstrip('\n')
root = build(s, 0, len(s) - 1)
ansarun = []
for _ in range(int(input())):
	templist = list(input().split())
	if templist[0] == '1':
		root = update(root, int(templist[1]) - 1, templist[2])
	else:
		temp1 = query(root, int(templist[1]) - 1, int(templist[2]) - 1)
		total = 0
		for i in temp1:
			if i:
				total += 1
		ansarun.append(total)
for i in ansarun:
	print(i)


import sys
from operator import add

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

def list2d(a, b, c):
	return [[c] * b for i in range(a)]

def list3d(a, b, c, d):
	return [[[d] * c for j in range(b)] for i in range(a)]

def list4d(a, b, c, d, e):
	return [[[[e] * d for j in range(c)] for j in range(b)] for i in range(a)]

def ceil(x, y=1):
	return int(-(-x // y))

def INT():
	return int(input())

def MAP():
	return map(int, input().split())

def LIST(N=None):
	return list(MAP()) if N is None else [INT() for i in range(N)]

def Yes():
	print('Yes')

def No():
	print('No')

def YES():
	print('YES')

def NO():
	print('NO')
sys.setrecursionlimit(10 ** 9)
INF = float('inf')
MOD = 10 ** 9 + 7

class SegTree:

	def __init__(self, n, func, init):
		self.n = n
		self.func = func
		self.init = init
		n2 = 1
		while n2 < n:
			n2 <<= 1
		self.n2 = n2
		self.tree = [self.init] * (n2 << 1)

	def update(self, i, x):
		i += self.n2
		self.tree[i] = x
		while i > 1:
			self.tree[i >> 1] = x = self.func(x, self.tree[i ^ 1])
			i >>= 1

	def query(self, a, b):
		l = a + self.n2
		r = b + self.n2
		s = self.init
		while l < r:
			if r & 1:
				r -= 1
				s = self.func(s, self.tree[r])
			if l & 1:
				s = self.func(s, self.tree[l])
				l += 1
			l >>= 1
			r >>= 1
		return s
A = [ord(s) - 97 for s in list(input())]
N = len(A)
st = [None] * 26
for i in range(26):
	st[i] = SegTree(N, add, 0)
for (i, a) in enumerate(A):
	st[a].update(i, 1)
for _ in range(INT()):
	(a, b, c) = input().split()
	if a == '1':
		b = int(b)
		cur = A[b - 1]
		nxt = ord(c) - 97
		st[cur].update(b - 1, 0)
		st[nxt].update(b - 1, 1)
		A[b - 1] = nxt
	else:
		b = int(b)
		c = int(c)
		cnt = 0
		for i in range(26):
			if st[i].query(b - 1, c) >= 1:
				cnt += 1
		print(cnt)


import sys
input = sys.stdin.readline
MOD = 1000000007
MOD2 = 998244353
ii = lambda : int(input().strip('\n'))
si = lambda : input().strip('\n')
dgl = lambda : list(map(int, input().strip('\n')))
f = lambda : map(int, input().strip('\n').split())
il = lambda : list(map(int, input().strip('\n').split()))
ls = lambda : list(input().strip('\n'))
lsi = lambda : [int(i) for i in ls()]
let = 'abcdefghijklmnopqrstuvwxyz'

def updateBIT(i, bit, val, n):
	while i <= n:
		bit[i] += val
		i += i & -i

def queryBIT(i, bit):
	ans = 0
	while i > 0:
		ans += bit[i]
		i -= i & -i
	return ans
s = ls()
n = len(s)
BIT = [[0] * (n + 1) for i in range(26)]
for i in range(1, n + 1):
	ch = ord(s[i - 1]) - ord('a')
	updateBIT(i, BIT[ch], 1, n)
for _ in range(ii()):
	(q, a, b) = input().strip('\r\n').split()
	if q == '1':
		updateBIT(int(a), BIT[ord(s[int(a) - 1]) - ord('a')], -1, n)
		updateBIT(int(a), BIT[ord(b) - ord('a')], 1, n)
		s[int(a) - 1] = b
	else:
		ans = 0
		for i in range(26):
			ans += queryBIT(int(b), BIT[i]) - queryBIT(int(a) - 1, BIT[i]) > 0
		print(ans)


from sys import stdin
input = stdin.readline

def fenwick(N):
	tree = [0] * (N + 1)

	def update(x, val=1):
		nonlocal N
		while x <= N:
			tree[x] += val
			x += x & -x

	def query(x):
		ans = 0
		while x > 0:
			ans += tree[x]
			x -= x & -x
		return ans
	return (update, query, tree)
s = [0] + list(input().strip())
ns = len(s)
ff = [fenwick(ns) for i in range(26)]
for i in range(1, ns):
	ff[ord(s[i]) - ord('a')][0](i, 1)
for _ in range(int(input())):
	(a, b, c) = input().split()
	if a == '1':
		b = int(b)
		if s[b] == c:
			continue
		ff[ord(s[b]) - ord('a')][0](b, -1)
		ff[ord(c) - ord('a')][0](b, 1)
		s[b] = c
	else:
		(b, c) = (int(b), int(c))
		r = 0
		for i in range(26):
			r += ff[i][1](c) - ff[i][1](b - 1) > 0
		print(r)


from string import ascii_lowercase as lows
import sys
input = sys.stdin.readline
N = 1 << 17

class bit:

	def __init__(self):
		self.l = [0] * (1 + N)

	def set(self, i):
		self.add(i, 1)

	def unset(self, i):
		self.add(i, -1)

	def add(self, i, val):
		while i <= N:
			self.l[i] += val
			i += i & -i

	def get(self, i):
		r = 0
		while i > 0:
			r += self.l[i]
			i -= i & -i
		return r

	def range(self, l, r):
		return self.get(r) - self.get(l - 1)
bits = {c: bit() for c in lows}
s = [c for c in input().strip()]
for (i, c) in enumerate(s):
	bits[c].set(i + 1)
q = int(input().strip())
for _ in range(q):
	ins = input().split()
	if ins[0] == '1':
		pos = int(ins[1])
		bits[s[pos - 1]].unset(pos)
		bits[ins[2]].set(pos)
		s[pos - 1] = ins[2]
	else:
		(l, r) = map(int, ins[1:])
		sm = 0
		for b in bits.values():
			if b.range(l, r) > 0:
				sm += 1
		print(sm)


from sys import stdin
input = 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
s = list(input().rstrip())
n = len(s)
fenwick = [Bit(n + 1) for i in range(26)]
for i in range(n):
	fenwick[ord(s[i]) - ord('a')].add(i + 1, 1)
q = int(input())
for _ in range(q):
	(a, b, c) = input().rstrip().split()
	if a == '1':
		b = int(b)
		fenwick[ord(s[b - 1]) - ord('a')].add(b, -1)
		fenwick[ord(c) - ord('a')].add(b, 1)
		s[b - 1] = c
	else:
		ans = 0
		b = int(b)
		c = int(c)
		for i in range(26):
			ans += fenwick[i].sum(c) - fenwick[i].sum(b - 1) > 0
		print(ans)


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def RL():
	return map(int, sys.stdin.readline().rstrip().split())

def RLL():
	return list(RL())

def N():
	return int(input())

def comb(n, m):
	return factorial(n) / (factorial(m) * factorial(n - m)) if n >= m else 0

def perm(n, m):
	return factorial(n) // factorial(n - m) if n >= m else 0

def mdis(x1, y1, x2, y2):
	return abs(x1 - x2) + abs(y1 - y2)

def toord(c):
	return ord(c) - ord('a')

def lcm(a, b):
	return a * b // gcd(a, b)
mod = 998244353
INF = float('inf')
from math import factorial, sqrt, ceil, floor, gcd
from collections import Counter, defaultdict, deque
from heapq import heapify, heappop, heappush
from math import log2

def main():
	s = list(input())
	le = len(s)
	deep = 2 ** ceil(log2(le))
	lbarr = [[0] * 26 for _ in range(deep + 1)]

	def lb_add(x, ind):
		while x < deep + 1:
			lbarr[x][ind] += 1
			x = x + (x & -x)

	def lb_ask(x):
		res = [0] * 26
		while x > 0:
			now = lbarr[x]
			for i in range(26):
				res[i] += now[i]
			x = x - (x & -x)
		return res

	def lb_change(x, new, old):
		lb_add(x, toord(new))
		while x < deep + 1:
			lbarr[x][toord(old)] -= 1
			x = x + (x & -x)
	for i in range(1, le + 1):
		lb_add(i, toord(s[i - 1]))
	q = N()
	for _ in range(q):
		now = input().split(' ')
		n_id = int(now[0])
		if n_id == 1:
			(ind, ch) = (int(now[1]), now[2])
			lb_change(ind, ch, s[ind - 1])
			s[ind - 1] = ch
		elif n_id == 2:
			(l, r) = (int(now[1]), int(now[2]))
			(rarr, larr) = (lb_ask(r), lb_ask(l - 1))
			res = 0
			for i in range(26):
				if rarr[i] - larr[i] > 0:
					res += 1
			print(res)
main()


import sys
input = sys.stdin.readline

class SegmentTree:

	def __init__(self, n):
		self.n = 2 ** (n - 1).bit_length()
		self.data = [0 for _ in range(2 * self.n)]

	def build(self, arr):
		for i in range(len(arr)):
			self.data[self.n + i] = 1 << arr[i]
		for i in range(self.n - 1, 0, -1):
			self.data[i] = self.data[i << 1] | self.data[i << 1 | 1]

	def updateTreeNode(self, p, value):
		p = p + self.n
		self.data[p] = 1 << value
		while p > 1:
			self.data[p >> 1] = self.data[p] | self.data[p ^ 1]
			p >>= 1

	def __repr__(self):
		return ' '.join((str(bin(val).count('1')) for val in self.data))

	def query(self, l, r):
		ans = 0
		l += self.n
		r += self.n
		while l < r:
			if l & 1:
				ans |= self.data[l]
				l += 1
			if r & 1:
				r -= 1
				ans |= self.data[r]
			l >>= 1
			r >>= 1
		return ans
aval = ord('a')
s = [ord(c) - aval for c in input()[:-1]]
segTree = SegmentTree(len(s))
segTree.build(s)
for _ in range(int(input()[:-1])):
	(q, a, b) = input()[:-1].split()
	if q == '1':
		segTree.updateTreeNode(int(a) - 1, ord(b) - aval)
	else:
		print(bin(segTree.query(int(a) - 1, int(b))).count('1'))


import sys

def rint():
	return map(int, sys.stdin.readline().split())

def input():
	return sys.stdin.readline().rstrip('\n')

def lsbz(n):
	return n + 1 & ~n

def bit_sum(tree, i):
	ans = 0
	while i >= 0:
		ans += tree[i]
		i -= lsbz(i)
	return ans

def bit_sum_dot(tree, i):
	return bit_sum(tree, i) - bit_sum(tree, i - 1)

def bit_update(tree, i, diff):
	while i < len(tree):
		tree[i] += diff
		i += lsbz(i)

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

def replace(cmd):
	pos = int(cmd[1]) - 1
	c = a2i(cmd[2])
	old_c = s[pos]
	if old_c == c:
		return
	bit_update(tree[old_c], pos, -1)
	bit_update(tree[c], pos, 1)
	s[pos] = c

def calc(cmd):
	l = int(cmd[1]) - 1
	r = int(cmd[2]) - 1
	ans = 0
	for i in range(a_len):
		if bit_sum(tree[i], r) - bit_sum(tree[i], l - 1):
			ans += 1
	return ans
a_len = a2i('z') + 1
s = [a2i(a) for a in input()]
tree = [[0 for i in range(len(s))] for j in range(a_len)]
for i in range(len(s)):
	bit_update(tree[s[i]], i, 1)
q = int(input())
for _ in range(q):
	cmd = sys.stdin.readline().split()
	if cmd[0] == '1':
		replace(cmd)
	if cmd[0] == '2':
		print(calc(cmd))


import sys
input = sys.stdin.readline
s = list(str(input()))
n = len(s)
q = int(input())
s = [{ord(c) - ord('a')} for c in s]

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[2 * k + 1], seg[2 * k + 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()
num = 2 ** (n - 1).bit_length()
seg = [ide_ele] * 2 * num
init(s)
for _ in range(q):
	(t, x, y) = map(str, input().split())
	if t == '1':
		i = int(x) - 1
		c = {ord(y) - ord('a')}
		update(i, c)
	else:
		l = int(x) - 1
		r = int(y) - 1
		print(len(query(l, r + 1)))


import sys

def build_seg_tree(n, s):
	tree = [0 for _ in range(2 * n)]
	base = ord('a')
	for i in range(n, 2 * n):
		tree[i] = 1 << s[i - n] - base
	for i in range(n - 1, 0, -1):
		tree[i] = tree[2 * i] | tree[2 * i + 1]
	return tree

def modify_seg_tree(tree, pos, char):
	n = len(tree) >> 1
	pos += n
	base = ord('a')
	tree[pos] = 1 << ord(char) - base
	while pos > 1:
		pos >>= 1
		tree[pos] = tree[2 * pos] | tree[2 * pos + 1]
	return

def query_seg_tree(tree, lptr, rptr):
	res = 0
	n = len(tree) >> 1
	lptr += n
	rptr += n
	while lptr < rptr:
		if lptr % 2 == 1:
			res |= tree[lptr]
			lptr += 1
		if rptr % 2 == 1:
			rptr -= 1
			res |= tree[rptr]
		lptr >>= 1
		rptr >>= 1
	return bin(res).count('1')

def main():
	s = sys.stdin.buffer.readline().rstrip()
	tree = build_seg_tree(len(s), s)
	q = int(sys.stdin.readline())
	for i in range(q):
		(type, pl, cr) = sys.stdin.readline().split()
		if type == '1':
			modify_seg_tree(tree, int(pl) - 1, cr)
		else:
			print(query_seg_tree(tree, int(pl) - 1, int(cr)))
	return
main()


def update(v, w, s):
	while v <= length:
		l[s][v] += w
		v += v & -v

def get_value(v, s):
	ans = 0
	while v != 0:
		ans += l[s][v]
		v -= v & -v
	return ans
from sys import stdin, stdout
s = list(stdin.readline().strip())
q = int(stdin.readline())
length = len(s)
l = [[0 for i in range(length + 1)] for _ in range(26)]
for i in range(length):
	x = ord(s[i]) - 97
	update(i + 1, 1, x)
for _ in range(q):
	(n, m, k) = stdin.readline().split()
	if n == '1':
		a = s[int(m) - 1]
		(x, y) = (ord(a) - 97, ord(k) - 97)
		update(int(m), -1, x)
		update(int(m), 1, y)
		s[int(m) - 1] = k
	else:
		count = 0
		(left, r) = (int(m), int(k))
		for i in range(26):
			if get_value(r, i) - get_value(left - 1, i) >= 1:
				count += 1
		print(count)


import os
from io import BytesIO
input = BytesIO(os.read(0, os.fstat(0).st_size)).readline

def update(arr, index, value):
	while index < len(arr):
		arr[index] += value
		index = index | index + 1

def sum(arr, index):
	result = 0
	while index >= 0:
		result += arr[index]
		index = (index & index + 1) - 1
	return result

def init(fenwick, char, items):
	if char not in fenwick:
		fenwick[char] = [0] * items

def main():
	s = list(input().rstrip().decode('utf-8'))
	fenwick = {}
	for (index, char) in enumerate(s):
		init(fenwick, char, len(s))
		update(fenwick[char], index, 1)
	q = int(input())
	while q:
		q -= 1
		inp = [x.decode('utf-8') for x in input().split()]
		if inp[0] == '2':
			(t, l, r) = map(int, inp)
			l -= 1
			r -= 1
			count = 0
			for tree in fenwick.values():
				if sum(tree, r) - sum(tree, l - 1) > 0:
					count += 1
			print(count)
		else:
			(t, idx, ch) = (inp[0], int(inp[1]), inp[2])
			idx -= 1
			init(fenwick, s[idx], len(s))
			init(fenwick, ch, len(s))
			update(fenwick[s[idx]], idx, -1)
			update(fenwick[ch], idx, 1)
			s[idx] = ch
main()


import os
from io import BytesIO, IOBase
import sys

class SortedList:

	def __init__(self, iterable=None, _load=200):
		if iterable is None:
			iterable = []
		values = sorted(iterable)
		self._len = _len = len(values)
		self._load = _load
		self._lists = _lists = [values[i:i + _load] for i in range(0, _len, _load)]
		self._list_lens = [len(_list) for _list in _lists]
		self._mins = [_list[0] for _list in _lists]
		self._fen_tree = []
		self._rebuild = True

	def _fen_build(self):
		self._fen_tree[:] = self._list_lens
		_fen_tree = self._fen_tree
		for i in range(len(_fen_tree)):
			if i | i + 1 < len(_fen_tree):
				_fen_tree[i | i + 1] += _fen_tree[i]
		self._rebuild = False

	def _fen_update(self, index, value):
		if not self._rebuild:
			_fen_tree = self._fen_tree
			while index < len(_fen_tree):
				_fen_tree[index] += value
				index |= index + 1

	def _fen_query(self, end):
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		x = 0
		while end:
			x += _fen_tree[end - 1]
			end &= end - 1
		return x

	def _fen_findkth(self, k):
		_list_lens = self._list_lens
		if k < _list_lens[0]:
			return (0, k)
		if k >= self._len - _list_lens[-1]:
			return (len(_list_lens) - 1, k + _list_lens[-1] - self._len)
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		idx = -1
		for d in reversed(range(len(_fen_tree).bit_length())):
			right_idx = idx + (1 << d)
			if right_idx < len(_fen_tree) and k >= _fen_tree[right_idx]:
				idx = right_idx
				k -= _fen_tree[idx]
		return (idx + 1, k)

	def _delete(self, pos, idx):
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len -= 1
		self._fen_update(pos, -1)
		del _lists[pos][idx]
		_list_lens[pos] -= 1
		if _list_lens[pos]:
			_mins[pos] = _lists[pos][0]
		else:
			del _lists[pos]
			del _list_lens[pos]
			del _mins[pos]
			self._rebuild = True

	def _loc_left(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(lo, pos) = (-1, len(_lists) - 1)
		while lo + 1 < pos:
			mi = lo + pos >> 1
			if value <= _mins[mi]:
				pos = mi
			else:
				lo = mi
		if pos and value <= _lists[pos - 1][-1]:
			pos -= 1
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value <= _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def _loc_right(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(pos, hi) = (0, len(_lists))
		while pos + 1 < hi:
			mi = pos + hi >> 1
			if value < _mins[mi]:
				hi = mi
			else:
				pos = mi
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value < _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def add(self, value):
		_load = self._load
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len += 1
		if _lists:
			(pos, idx) = self._loc_right(value)
			self._fen_update(pos, 1)
			_list = _lists[pos]
			_list.insert(idx, value)
			_list_lens[pos] += 1
			_mins[pos] = _list[0]
			if _load + _load < len(_list):
				_lists.insert(pos + 1, _list[_load:])
				_list_lens.insert(pos + 1, len(_list) - _load)
				_mins.insert(pos + 1, _list[_load])
				_list_lens[pos] = _load
				del _list[_load:]
				self._rebuild = True
		else:
			_lists.append([value])
			_mins.append(value)
			_list_lens.append(1)
			self._rebuild = True

	def discard(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_right(value)
			if idx and _lists[pos][idx - 1] == value:
				self._delete(pos, idx - 1)

	def remove(self, value):
		_len = self._len
		self.discard(value)
		if _len == self._len:
			raise ValueError('{0!r} not in list'.format(value))

	def pop(self, index=-1):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		value = self._lists[pos][idx]
		self._delete(pos, idx)
		return value

	def bisect_left(self, value):
		(pos, idx) = self._loc_left(value)
		return self._fen_query(pos) + idx

	def bisect_right(self, value):
		(pos, idx) = self._loc_right(value)
		return self._fen_query(pos) + idx

	def count(self, value):
		return self.bisect_right(value) - self.bisect_left(value)

	def __len__(self):
		return self._len

	def __getitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		return self._lists[pos][idx]

	def __delitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		self._delete(pos, idx)

	def __contains__(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_left(value)
			return idx < len(_lists[pos]) and _lists[pos][idx] == value
		return False

	def __iter__(self):
		return (value for _list in self._lists for value in _list)

	def __reversed__(self):
		return (value for _list in reversed(self._lists) for value in reversed(_list))

	def __repr__(self):
		return 'SortedList({0})'.format(list(self))

def main():
	s = list(map(lambda x: ord(x) - ord('a'), input()))
	arr = [[] for _ in range(26)]
	for (i, item) in enumerate(s):
		arr[item].append(i)
	for i in range(26):
		arr[i] = SortedList(arr[i])
	q = int(input())
	for _ in range(q):
		(a, b, c) = input().split()
		if a == '1':
			b = int(b) - 1
			c = ord(c) - ord('a')
			arr[s[b]].remove(b)
			s[b] = c
			arr[s[b]].add(b)
		else:
			ans = 0
			b = int(b) - 1
			c = int(c) - 1
			for i in range(26):
				z = arr[i].bisect_left(b)
				if z != len(arr[i]) and arr[i][z] <= c:
					ans += 1
			print(ans)
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


class SegmentTree:
	ord_a = ord('a')

	def __init__(self, arr):
		temp = [1 << ord(x) - self.ord_a for x in arr]
		self.n = 1 << len(bin(len(arr) - 1)) - 2
		self.d = [0] * self.n + temp + [0] * (self.n - len(arr))
		for i in range(self.n - 1, 0, -1):
			self.d[i] = self.d[2 * i + 1] | self.d[2 * i]

	def update(self, pos, ch):
		pos += self.n
		self.d[pos] = 1 << ord(ch[0]) - self.ord_a
		while pos > 1:
			pos >>= 1
			self.d[pos] = self.d[2 * pos + 1] | self.d[2 * pos]

	def query(self, l, r):
		l += self.n
		r += self.n
		s = self.d[r] | self.d[l]
		while l < r - 1:
			if r & 1:
				s |= self.d[r - 1]
			if not l & 1:
				s |= self.d[l + 1]
			l >>= 1
			r >>= 1
		return bin(s).count('1')
tree = SegmentTree(input())
for t in range(int(input())):
	[type, q1, q2] = input().split()
	if not int(type) & 1:
		print(tree.query(int(q1) - 1, int(q2) - 1))
	else:
		tree.update(int(q1) - 1, q2)


import os, sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
from types import GeneratorType

def iterative(f, stack=[]):

	def wrapped_func(*args, **kwargs):
		if stack:
			return f(*args, **kwargs)
		to = f(*args, **kwargs)
		while True:
			if type(to) is GeneratorType:
				stack.append(to)
				to = next(to)
				continue
			stack.pop()
			if not stack:
				break
			to = stack[-1].send(to)
		return to
	return wrapped_func

@iterative
def build_segment(a, tree, i_tree, right, left):
	if right == left:
		tree[i_tree] = 1 << a[right]
		yield
	else:
		mid = (right + left) // 2
		yield build_segment(a, tree, 2 * i_tree, right, mid)
		yield build_segment(a, tree, 2 * i_tree + 1, mid + 1, left)
		if tree[i_tree * 2] == 67108863 or tree[i_tree * 2 + 1] == 67108863:
			tree[i_tree] = 67108863
		else:
			tree[i_tree] = tree[i_tree * 2] | tree[i_tree * 2 + 1]
		yield

@iterative
def update(a, tree, i_tree, left, right, i, ch):
	if right == left == i:
		tree[i_tree] = 1 << ch
	elif left <= i <= right:
		mid = (right + left) // 2
		yield update(a, tree, i_tree * 2, left, mid, i, ch)
		yield update(a, tree, i_tree * 2 + 1, mid + 1, right, i, ch)
		if tree[i_tree * 2] == 67108863 or tree[i_tree * 2 + 1] == 67108863:
			tree[i_tree] = 67108863
		else:
			tree[i_tree] = tree[i_tree * 2] | tree[i_tree * 2 + 1]
	yield

@iterative
def querry(tree, i_tree, left, right, ql, qr, s):
	if qr < left or ql > right:
		yield
	if ql <= left and right <= qr:
		if s[0] < 67108863:
			s[0] |= tree[i_tree]
	else:
		mid = (right + left) // 2
		yield querry(tree, 2 * i_tree, left, mid, ql, qr, s)
		yield querry(tree, 2 * i_tree + 1, mid + 1, right, ql, qr, s)
	yield

def dtb(n):
	return bin(n).replace('0b', '')
a = [ord(i) - 97 for i in input()]
t = [0] * (4 * len(a) + 1)
build_segment(a, t, 1, 0, len(a) - 1)
chec = dict()
for _ in range(int(input())):
	(ck, x, y) = input().split()
	if int(ck) == 1:
		chec[int(x)] = y
	else:
		for i in chec:
			x1 = i
			y1 = chec[i]
			if a[int(x1) - 1] == ord(y1) - 97:
				continue
			update(a, t, 1, 0, len(a) - 1, int(x1) - 1, ord(y1) - 97)
			a[int(x1) - 1] = ord(y1) - 97
		s = [0]
		querry(t, 1, 0, len(a) - 1, int(x) - 1, int(y) - 1, s)
		print(dtb(s[0]).count('1'))
		chec = dict()


import sys, math, itertools
from collections import Counter, deque, defaultdict
from bisect import bisect_left, bisect_right
from heapq import heappop, heappush, heapify
from copy import deepcopy
mod = 10 ** 9 + 7
INF = float('inf')

def inp():
	return int(sys.stdin.readline())

def inpl():
	return list(map(int, sys.stdin.readline().split()))

def inpl_1():
	return list(map(lambda x: int(x) - 1, sys.stdin.readline().split()))

def inps():
	return sys.stdin.readline()

def inpsl(x):
	tmp = sys.stdin.readline()
	return list(tmp[:x])

def err(x):
	print(x)
	exit()
import sys
input = sys.stdin.readline

def solve():
	ordA = ord('a')
	Ss = input().rstrip()
	N = len(Ss)
	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(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()


s = list(input())
t = [0 for i in range(len(s) * 4)]
bits = dict()
b = 1
for i in range(97, 123):
	bits[chr(i)] = b
	b <<= 1

def bit_repr(a):
	return bits[a]

def popcount(i):
	i = i - (i >> 1 & 1431655765)
	i = (i & 858993459) + (i >> 2 & 858993459)
	return ((i + (i >> 4) & 252645135) * 16843009 & 4294967295) >> 24

def build(A, v, t_left, t_right):
	if t_left == t_right:
		t[v] |= bit_repr(A[t_left])
		return
	left_son = (v << 1) + 1
	right_son = left_son + 1
	t_mid = t_left + t_right >> 1
	build(A, left_son, t_left, t_mid)
	build(A, right_son, t_mid + 1, t_right)
	t[v] = t[left_son] | t[right_son]

def _update(v, t_left, t_right, index, val):
	while t_left != t_right:
		t_mid = (t_left + t_right) // 2
		left_son = (v << 1) + 1
		right_son = left_son + 1
		if index > t_mid:
			t_left = t_mid + 1
			v = right_son
		else:
			t_right = t_mid
			v = left_son
	t[v] = bit_repr(val)
	while v:
		v = v - 1 >> 1
		left_son = (v << 1) + 1
		right_son = left_son + 1
		t[v] = t[left_son] | t[right_son]

def update(index, val):
	_update(0, 0, len(s) - 1, index - 1, val)

def get_set(v, t_left, t_right, left, right):
	if left > right:
		return 0
	if t_left == left and t_right == right:
		return t[v]
	t_mid = t_left + t_right >> 1
	left_son = (v << 1) + 1
	right_son = left_son + 1
	a = get_set(left_son, t_left, t_mid, left, min(right, t_mid))
	b = get_set(right_son, t_mid + 1, t_right, max(left, t_mid + 1), right)
	return a | b

def count(l, r):
	return popcount(get_set(0, 0, len(s) - 1, l - 1, r - 1))

def get_request():
	req = iter(input().split())
	token = int(next(req))
	if token - 1:
		(l, r) = list(map(int, req))
		return (token, l, r)
	else:
		pos = int(next(req))
		sym = next(req)
		return (token, pos, sym)

def response(req):
	(token, a, b) = req
	if token - 1:
		print(count(a, b))
	else:
		update(a, b)
build(s, 0, 0, len(s) - 1)
n = int(input())
for i in range(n):
	req = get_request()
	response(req)


import sys

def upd(bit, idx, inc):
	while idx < len(bit):
		bit[idx] += inc
		idx += idx & -idx

def query(bit, idx):
	ret = 0
	while idx > 0:
		ret += bit[idx]
		idx -= idx & -idx
	return ret
input = sys.stdin.readline
inp = list(input().strip())
dic = {}
for i in range(26):
	cur = chr(ord('a') + i)
	arr = [0 for i in range(len(inp) + 1)]
	dic[cur] = arr
for i in range(len(inp)):
	upd(dic[inp[i]], i + 1, 1)
q = int(input().strip())
for _ in range(q):
	(a, b, c) = input().strip().split()
	if a == '1':
		idx = int(b)
		cur_ch = inp[idx - 1]
		upd(dic[cur_ch], idx, -1)
		upd(dic[c], idx, 1)
		inp[idx - 1] = c
	else:
		l = int(b)
		r = int(c)
		ans = 0
		for x in dic:
			ll = query(dic[x], l)
			rr = query(dic[x], r)
			if ll == rr and ll != 0:
				if inp[l - 1] == x:
					ans += 1
			elif rr - ll > 0:
				ans += 1
		print(ans)


from array import array
from collections import deque
letters = array('B', (ord(letter) for letter in input()))
q = int(input())
masks = {}
for i in range(ord('a'), ord('z') + 1):
	masks[i] = 1 << i - ord('a')

def count_bits(value):
	counter = 0
	while value:
		if value % 2:
			counter += 1
		value >>= 1
	return counter

def init_heap(heap, k):
	for index in range(2 ** k - 1, 2 ** k - 1 + 2 ** k):
		array_index = index - 2 ** k + 1
		if array_index < len(letters):
			heap[index] = masks[letters[array_index]]
		else:
			heap[index] = 0
	for level in range(k - 1, -1, -1):
		for index in range(2 ** level - 1, 2 ** level - 1 + 2 ** level):
			heap[index] = heap[2 * index + 1] | heap[2 * index + 2]

def get_heap(array):
	k = 0
	while 2 ** k < len(array):
		k += 1
	heap_size = 2 ** (k + 1) - 1
	tree = heap_size * [0]
	init_heap(tree, k)
	return (tree, k)

def update_heap(heap, array_index, k):
	index = 2 ** k - 1 + array_index
	heap[index] = masks[letters[array_index]]
	while index:
		index = (index + 1) // 2 - 1
		tree[index] = tree[2 * index + 1] | tree[2 * index + 2]

def get(l, r, heap, k):
	result = 0
	q = deque([(l, r, 0, 0, 2 ** k)])
	while q:
		(l, r, index, L, R) = q.pop()
		if l == L and r == R:
			result |= heap[index]
		else:
			M = (L + R) // 2
			if r <= M:
				q.appendleft((l, r, 2 * index + 1, L, M))
			elif M <= l:
				q.appendleft((l, r, 2 * index + 2, M, R))
			else:
				q.appendleft((l, M, 2 * index + 1, L, M))
				q.appendleft((M, r, 2 * index + 2, M, R))
	return result
(tree, k) = get_heap(letters)
for _ in range(q):
	(query, a, b) = input().split()
	if query == '1':
		index = int(a) - 1
		letters[index] = ord(b)
		update_heap(tree, index, k)
	else:
		start_index = int(a) - 1
		end_index = int(b) - 1
		print(count_bits(get(start_index, end_index + 1, tree, k)))


s = input()
q = int(input())
T = []
for i in range(4 * len(s) + 10):
	T.append(0)

def create(rt, l, r):
	if l == r:
		T[rt] = 1 << ord(s[l - 1]) - 97
		return
	mid = (l + r) // 2
	create(rt << 1, l, mid)
	create(rt << 1 | 1, mid + 1, r)
	T[rt] = T[rt << 1] | T[rt << 1 | 1]

def update(rt, l, r, pos, now):
	if l == r:
		T[rt] = 1 << ord(now) - 97
		return
	mid = (l + r) // 2
	if pos <= mid:
		update(rt << 1, l, mid, pos, now)
	else:
		update(rt << 1 | 1, mid + 1, r, pos, now)
	T[rt] = T[rt << 1] | T[rt << 1 | 1]

def cal(rt, l, r, L, R):
	if l == L and R == r:
		return T[rt]
	mid = (l + r) // 2
	if R <= mid:
		return cal(rt << 1, l, mid, L, R)
	elif L > mid:
		return cal(rt << 1 | 1, mid + 1, r, L, R)
	else:
		return cal(rt << 1, l, mid, L, mid) | cal(rt << 1 | 1, mid + 1, r, mid + 1, R)
n = len(s)
create(1, 1, n)
for i in range(q):
	str = input().split()
	if str[0] == '1':
		pos = int(str[1])
		update(1, 1, n, pos, str[2])
	else:
		l = int(str[1])
		r = int(str[2])
		res = cal(1, 1, n, l, r)
		ans = 0
		while res > 0:
			if res % 2 == 1:
				ans += 1
			res //= 2
		print(ans)


from sys import stdin

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

def count_bits(value):
	counter = 0
	while value:
		counter += value & 1
		value >>= 1
	return counter

class SegmentTree:

	def __init__(self, values, default, func):
		k = 0
		while 2 ** k < len(values):
			k += 1
		heap = (2 ** k - 1) * [default] + list(values) + (2 ** k - len(values)) * [default]
		for index in range(2 ** k - 1 - 1, -1, -1):
			heap[index] = func(heap[2 * index + 1], heap[2 * index + 2])
		self._length = len(values)
		self.func = func
		self.heap = heap
		self.k = k
		self.default = default

	def __getitem__(self, indexer):
		shift = 2 ** self.k - 1
		if isinstance(indexer, int):
			return self.heap[shift + indexer]
		elif isinstance(indexer, slice):
			(left, right) = (shift + indexer.start, shift + indexer.stop - 1)
			if left > right:
				return self.default
			func = self.func
			heap = self.heap
			res = func(heap[left], heap[right])
			while left < right:
				if ~(left & 1):
					res = func(res, heap[left])
					left += 1
				if right & 1:
					res = func(res, heap[right])
					right -= 1
				left = (left + 1) // 2 - 1
				right = (right + 1) // 2 - 1
				if left == right:
					res = func(res, heap[left])
			return res
		raise TypeError()

	def __setitem__(self, array_index, value):
		if array_index > len(self):
			raise IndexError
		index = 2 ** self.k - 1 + array_index
		heap = self.heap
		func = self.func
		heap[index] = value
		while index:
			index = (index + 1) // 2 - 1
			heap[index] = func(heap[2 * index + 1], heap[2 * index + 2])

	def __len__(self):
		return self._length
letters = stdin.readline().strip()
array = [char_bit(c) for c in letters]
segment_tree = SegmentTree(array, default=0, func=lambda x, y: x | y)
q = int(input())
for _ in range(q):
	(query, a, b) = stdin.readline().split()
	if query == '1':
		index = int(a) - 1
		segment_tree[index] = char_bit(b)
	else:
		start = int(a) - 1
		stop = int(b)
		print(count_bits(segment_tree[start:stop]))


def countSetBits(n):
	count = 0
	while n:
		count += n & 1
		n >>= 1
	return count

def segtree(tree, l, r, s, pos):
	if l == r:
		tree[pos] = 2 ** (ord(s[l]) - 97)
		return
	m = (l + r) // 2
	segtree(tree, l, m, s, 2 * pos + 1)
	segtree(tree, m + 1, r, s, 2 * pos + 2)
	tree[pos] = tree[2 * pos + 1] | tree[2 * pos + 2]

def update(tree, l, r, pos, i, c):
	if i < l or i > r:
		return
	if l == r:
		tree[pos]
		tree[pos] = 2 ** (ord(c) - 97)
		return
	m = (l + r) // 2
	update(tree, l, m, 2 * pos + 1, i, c)
	update(tree, m + 1, r, 2 * pos + 2, i, c)
	tree[pos] = tree[2 * pos + 1] | tree[2 * pos + 2]
	return

def search(tree, l, r, i, j, pos):
	if r < i or j < l:
		return 0
	elif i <= l and j >= r:
		return tree[pos]
	m = (l + r) // 2
	a = search(tree, l, m, i, j, 2 * pos + 1)
	b = search(tree, m + 1, r, i, j, 2 * pos + 2)
	return a | b
s = list(input())
n = len(s)
i = 0
while 2 ** i < n:
	i = i + 1
tree = [0] * (2 ** (i + 1) - 1)
segtree(tree, 0, n - 1, s, 0)
q = int(input())
for _ in range(q):
	l = list(map(str, input().split()))
	if l[0] == '1':
		update(tree, 0, n - 1, 0, int(l[1]) - 1, l[2])
	else:
		c = search(tree, 0, n - 1, int(l[1]) - 1, int(l[2]) - 1, 0)
		ans = countSetBits(c)
		print(ans)


import sys
input = sys.stdin.readline

class SegmentTree:

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

	def set(self, idx, x):
		x_val = ord(x) - 97
		self.tree[idx + self.size - 1] = 1 << x_val

	def build(self):
		for i in range(self.size - 2, -1, -1):
			self.tree[i] = self.tree[i * 2 + 1] | self.tree[i * 2 + 2]

	def update(self, idx, x):
		idx += self.size - 1
		x_val = ord(x) - 97
		self.tree[idx] = 1 << x_val
		while idx > 0:
			idx = (idx - 1) // 2
			self.tree[idx] = self.tree[idx * 2 + 1] | self.tree[idx * 2 + 2]

	def query(self, l, r):
		(left, right) = (l + self.size, r + self.size)
		ret = 0
		while left < right:
			if right & 1:
				right -= 1
				ret |= self.tree[right - 1]
			if left & 1:
				ret |= self.tree[left - 1]
				left += 1
			left >>= 1
			right >>= 1
		return ret

def main():
	S = list(input().rstrip())
	Q = int(input())
	queries = tuple((input().split() for _ in range(Q)))
	seg = SegmentTree(len(S))
	for (i, s) in enumerate(S):
		seg.set(i, s)
	seg.build()
	ans = []
	for (q_type, var1, var2) in queries:
		if q_type == '1':
			(idx, char) = (int(var1) - 1, var2)
			seg.update(idx, char)
		else:
			(left, right) = (int(var1) - 1, int(var2))
			x = seg.query(left, right)
			cnt = bin(x)[2:].count('1')
			ans.append(cnt)
	print('\n'.join(map(str, ans)))
main()


import math
import bisect
from functools import reduce
import sys
from collections import defaultdict
input = sys.stdin.readline

def inn():
	return int(input())

def inl():
	return list(map(int, input().split()))
MOD = 10 ** 9 + 7
INF = inf = 10 ** 18 + 5
s = list(input().strip())
n = len(s)
t = [[0] * 26 for i in range(2 * n)]
for i in range(n):
	t[i + n][ord(s[i]) - 97] = 1

def build():
	for i in range(n - 1, 0, -1):
		for j in range(26):
			t[i][j] = t[i << 1][j] + t[i << 1 | 1][j]

def modify(p, val):
	t[p + n][ord(s[p]) - 97] = 0
	t[p + n][ord(val) - 97] = 1
	s[p] = val
	p = p + n
	while p > 1:
		for i in range(26):
			t[p >> 1][i] = t[p][i] + t[p ^ 1][i]
		p >>= 1

def query(l, r):
	res = [0] * 26
	l += n
	r += n
	while l < r:
		if l & 1:
			for i in range(26):
				res[i] += t[l][i]
			l += 1
		if r & 1:
			r -= 1
			for i in range(26):
				res[i] += t[r][i]
		l >>= 1
		r >>= 1
	return res
build()
for q in range(inn()):
	(tp, l, r) = input().split()
	tp = int(tp)
	l = int(l)
	if tp == 1:
		modify(l - 1, r)
	elif tp == 2:
		r = int(r)
		res = query(l - 1, r)
		c = len([i for i in range(26) if res[i] > 0])
		print(c)


import os, sys
from io import IOBase, BytesIO
py2 = round(0.5)
if py2:
	from future_builtins import ascii, filter, hex, map, oct, zip
	range = xrange
BUFSIZE = 8192

class FastIO(BytesIO):
	newlines = 0

	def __init__(self, file):
		self._file = file
		self._fd = file.fileno()
		self.writable = 'x' in file.mode or 'w' in file.mode
		self.write = super(FastIO, self).write if self.writable else None

	def _fill(self):
		s = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
		self.seek((self.tell(), self.seek(0, 2), super(FastIO, self).write(s))[0])
		return s

	def read(self):
		while self._fill():
			pass
		return super(FastIO, self).read()

	def readline(self):
		while self.newlines == 0:
			s = self._fill()
			self.newlines = s.count(b'\n') + (not s)
		self.newlines -= 1
		return super(FastIO, self).readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.getvalue())
			(self.truncate(0), self.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		if py2:
			self.write = self.buffer.write
			self.read = self.buffer.read
			self.readline = self.buffer.readline
		else:
			self.write = lambda s: self.buffer.write(s.encode('ascii'))
			self.read = lambda : self.buffer.read().decode('ascii')
			self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
import sys

class ostream:

	def __lshift__(self, a):
		sys.stdout.write(str(a))
		return self
cout = ostream()
endl = '\n'
dv = str(input())
n = len(dv)
v = {}
for i in range(n):
	v[i] = dv[i]
q = int(input())
tree = [[0 for j in range(26)] for i in range(4 * n + 5)]
node = {}
aze = {}
aze[0] = (0, n - 1)

def build():
	r = [0]
	while r:
		i = r.pop()
		(s, e) = aze[i]
		if e < s:
			continue
		if e == s:
			b = ord(v[e]) - ord('a')
			tree[i][b] = 1
			node[e] = i
			j = (i - 1) // 2
			while j != 0:
				tree[j][b] += 1
				j = (j - 1) // 2
			tree[0][b] += 1
			continue
		aze[2 * i + 1] = (s, s + (e - s) // 2)
		aze[2 * i + 2] = (s + (e - s) // 2 + 1, e)
		r.append(2 * i + 1)
		r.append(2 * i + 2)
build()

def quer(s, e):
	r = [0]
	ans = [0 for i in range(26)]
	while r:
		i = r.pop()
		(ss, se) = aze[i]
		if s > se or e < ss:
			continue
		if s <= ss and e >= se:
			for j in range(26):
				ans[j] += tree[i][j]
			continue
		r.append(2 * i + 1)
		r.append(2 * i + 2)
	return 26 - ans.count(0)

def upd(i, p):
	j = node[i]
	b = ord(p) - ord('a')
	c = ord(v[i]) - ord('a')
	tree[j][c] -= 1
	tree[j][b] += 1
	j = (j - 1) // 2
	while j != 0:
		tree[j][c] -= 1
		tree[j][b] += 1
		j = (j - 1) // 2
	tree[0][c] -= 1
	tree[0][b] += 1
for i in range(q):
	(c, a, b) = input().split()
	if int(c) == 1:
		i = int(a) - 1
		upd(i, b)
		v[i] = b
	else:
		print(quer(int(a) - 1, int(b) - 1))


import os
import sys
from atexit import register
from io import StringIO
sys.stdout = StringIO()
register(lambda : os.write(1, sys.stdout.getvalue().encode()))
import math
t = [0 for i in range(int(4 * 100000.0))]

def build(arr, v, tl, tr):
	if tl == tr:
		t[v] = 1 << ord(arr[tl]) - 97
	else:
		tm = tl + tr >> 1
		build(arr, v << 1, tl, tm)
		build(arr, (v << 1) + 1, tm + 1, tr)
		t[v] = t[v << 1] | t[(v << 1) + 1]

def query(l, r, v, tl, tr):
	if r < l:
		return 0
	elif l == tl and r == tr:
		return t[v]
	else:
		tm = tl + tr >> 1
		return query(l, min(tm, r), v << 1, tl, tm) | query(max(tm + 1, l), r, (v << 1) + 1, tm + 1, tr)

def update(c, i, v, tl, tr):
	if tl == i == tr:
		t[v] = 1 << ord(c) - 97
	else:
		tm = tl + tr >> 1
		if i <= tm:
			update(c, i, v << 1, tl, tm)
		else:
			update(c, i, (v << 1) + 1, tm + 1, tr)
		t[v] = t[v << 1] | t[(v << 1) + 1]
s = input()
q = int(input())
build(s, 1, 0, len(s) - 1)
for _ in range(q):
	(a, b, c) = sys.stdin.readline().split()
	if int(a) == 1:
		pos = int(b)
		update(c, pos - 1, 1, 0, len(s) - 1)
	else:
		(l, r) = (int(b), int(c))
		n = query(l - 1, r - 1, 1, 0, len(s) - 1)
		ret = 0
		while n != 0:
			ret += n & 1
			n >>= 1
		print(ret)


from sys import stdin, stdout
read = stdin.readline
a = ord('a')

def get_bit(q):
	return 1 << ord(q) - a
SIZE = 1 << 17
TOP = 2 * SIZE - 2

def read_tree():
	bits = list(map(get_bit, read()[:-1]))
	bits += [0] * (2 * SIZE - len(bits))
	(i, j) = (0, SIZE)
	while i < j:
		bits[j] = bits[i] | bits[i + 1]
		j += 1
		i += 2
	return bits
bits = read_tree()

class Vertex:

	def __init__(self, index, size=SIZE, shift=0):
		self.size = size
		self.shift = shift
		self.index = index
		self.delta = -1 if index & 1 else 1

	def is_pair(self, vertex):
		return vertex.index == self.index + self.delta

	def is_same(self, vertex):
		return self.index == vertex.index

	def get_pair_bits(self):
		return bits[self.shift + self.index + self.delta]

	def get_bits(self):
		return bits[self.shift + self.index]

	def get_parent(self):
		return Vertex(self.index >> 1, self.size >> 1, self.shift + self.size)

	def set_bit(self, bit):
		i = self.shift + self.index
		if bit != bits[i]:
			self.del_bit(bits[i])
			self.add_bit(bit)

	def del_bit(self, bit):
		i = self.shift + self.index
		bits[i] ^= bit
		if i != TOP:
			if not self.get_pair_bits() & bit:
				self.get_parent().del_bit(bit)

	def add_bit(self, bit):
		i = self.shift + self.index
		if not bits[i] & bit:
			bits[i] |= bit
			if i != TOP:
				self.get_parent().add_bit(bit)

def sum_bits(b):
	return sum((b & 1 << k != 0 for k in range(26)))
for q in range(int(read())):
	(t, i, j) = read().split()
	i = int(i) - 1
	if t == '1':
		Vertex(i).set_bit(get_bit(j))
	else:
		j = int(j) - 1
		if i == j:
			stdout.write('1\n')
		else:
			(i, j) = (Vertex(i), Vertex(j))
			(bi, bj) = (i.get_bits(), j.get_bits())
			while not i.is_pair(j):
				if i.delta == 1:
					bi |= i.get_pair_bits()
				if j.delta == -1:
					bj |= j.get_pair_bits()
				(i, j) = (i.get_parent(), j.get_parent())
			stdout.write(str(sum_bits(bi | bj)) + '\n')


import sys
input = sys.stdin.readline

class SegmentTree:
	a = ord('a')

	def __init__(self):
		data = [1 << ord(c) - self.a for c in input()[:-1]]
		self.n = 1 << len(bin(len(data) - 1)) - 2
		self.data = [0] * self.n + data + [0] * (self.n - len(data))
		for k in range(self.n - 1, 0, -1):
			self.data[k] = self.data[2 * k + 1] | self.data[2 * k]

	def update(self, k, c):
		k += self.n
		self.data[k] = 1 << ord(c) - self.a
		while k > 1:
			k >>= 1
			self.data[k] = self.data[2 * k + 1] | self.data[2 * k]

	def query(self, l, r):
		l += self.n
		r += self.n
		s = self.data[r] | self.data[l]
		while l < r - 1:
			if r & 1:
				s |= self.data[r - 1]
			if not l & 1:
				s |= self.data[l + 1]
			l >>= 1
			r >>= 1
		return s
tree = SegmentTree()
for i in range(int(input())):
	q = input()[:-1].split()
	if q[0] == '1':
		tree.update(int(q[1]) - 1, q[2])
	else:
		s = tree.query(int(q[1]) - 1, int(q[2]) - 1)
		print(bin(s)[2:].count('1'))


def count_set_bits(i):
	count = 0
	while i:
		count += i & 1
		i >>= 1
	return count

class SegmentTree:

	def __init__(self, s):
		i_a = ord('a')
		source = [1 << ord(c) - i_a for c in s]
		self.n = 1 << (len(source) - 1).bit_length()
		self.data = [0] * self.n + source + [0] * (self.n - len(source))
		self.__build()

	def __build(self):
		for i in range(self.n - 1, -1, -1):
			self.data[i] = self.data[2 * i] | self.data[2 * i + 1]

	def update(self, pos, c):
		pos += self.n
		self.data[pos] = 1 << ord(c) - ord('a')
		while pos > 1:
			pos >>= 1
			self.data[pos] = self.data[2 * pos + 1] | self.data[2 * pos]

	def count_unique(self, l, r):
		l += self.n
		r += self.n
		res = self.data[l] | self.data[r]
		while l < r - 1:
			if not l & 1:
				res |= self.data[l + 1]
			if r & 1:
				res |= self.data[r - 1]
			l >>= 1
			r >>= 1
		return count_set_bits(res)
s = input()
q = int(input())
result = []
tree = SegmentTree(s)
while q:
	(com, a, b) = input().split()
	if com == '1':
		tree.update(int(a) - 1, b)
	else:
		result.append(tree.count_unique(int(a) - 1, int(b) - 1))
	q -= 1
for r in result:
	print(r)


import sys

class FTree:

	def __init__(self, f):
		self.n = len(f)
		self.ft = [0] * (self.n + 1)
		for i in range(1, self.n + 1):
			self.ft[i] += f[i - 1]
			if i + self.lsone(i) <= self.n:
				self.ft[i + self.lsone(i)] += self.ft[i]

	def lsone(self, s):
		return s & -s

	def query(self, i, j):
		if i > 1:
			return self.query(1, j) - self.query(1, i - 1)
		s = 0
		while j > 0:
			s += self.ft[j]
			j -= self.lsone(j)
		return s

	def update(self, i, v):
		while i <= self.n:
			self.ft[i] += v
			i += self.lsone(i)

	def select(self, k):
		lo = 1
		hi = self.n
		for i in range(30):
			mid = (lo + hi) // 2
			if self.query(1, mid) < k:
				lo = mid
			else:
				hi = mid
		return hi

class RUPQ:

	def __init__(self, n):
		self.ftree = FTree([0] * n)

	def query(self, i):
		return self.ftree.query(1, i)

	def update(self, i, j, v):
		self.ftree.update(i, v)
		self.ftree.update(j + 1, -v)

class RURQ:

	def __init__(self, n):
		self.f = FTree([0] * n)
		self.r = RUPQ(n)

	def query(self, i, j):
		if i > 1:
			return self.query(1, j) - self.query(1, i - 1)
		return self.r.query(j) * j - self.f.query(1, j)

	def update(self, i, j, v):
		self.r.update(i, j, v)
		self.f.update(i, v * (i - 1))
		self.f.update(j + 1, -1 * v * j)
f = [0, 1, 0, 1, 2, 3, 2, 1, 1, 0]
ft = FTree(f)
word = list(input())
w = len(word)
ftl = [[0] * w for i in range(26)]
fts = []
q = int(input())
for i in range(w):
	ftl[ord(word[i]) - 97][i] = 1
for i in range(26):
	fts.append(FTree(ftl[i]))
for i in range(q):
	d = sys.stdin.readline().split()
	if d[0] == '1':
		k = int(d[1])
		c = ord(d[2]) - 97
		fts[c].update(k, 1)
		oc = ord(word[k - 1]) - 97
		word[k - 1] = d[2]
		fts[oc].update(k, -1)
	else:
		(a, b) = (int(d[1]), int(d[2]))
		print(sum([fts[i].query(a, b) > 0 for i in range(26)]))


import sys
input = sys.stdin.readline

class SegmentTree:

	def __init__(self, init_val: 'initial value: Array or str', segfunc: 'operation unique in case', ide_ele: 'identity element corresponding init_val'=0):
		self.segfunc = segfunc
		self.size = 1 << (len(init_val) - 1).bit_length()
		self.ide_ele = ide_ele
		self.tree = self._build(init_val)

	def _build(self, init_val: 'Array or str'):
		tree = [self.ide_ele] * (2 * self.size)
		for (idx, val) in enumerate(init_val):
			val = 1 << ord(val) - 97
			tree[idx + self.size - 1] = val
		for idx in range(self.size - 2, -1, -1):
			tree[idx] = self.segfunc(tree[2 * idx + 1], tree[2 * idx + 2])
		return tree

	def update(self, idx: int, val):
		idx += self.size - 1
		val = 1 << ord(val) - 97
		self.tree[idx] = val
		while idx > 0:
			idx = (idx - 1) // 2
			self.tree[idx] = self.segfunc(self.tree[2 * idx + 1], self.tree[2 * idx + 2])

	def query(self, left: int, right: int):
		if left >= right:
			return self.ide_ele
		left += self.size
		right += self.size
		ret = self.ide_ele
		while left < right:
			if left & 1:
				ret = self.segfunc(ret, self.tree[left - 1])
				left += 1
			if right & 1:
				right -= 1
				ret = self.segfunc(ret, self.tree[right - 1])
			left >>= 1
			right >>= 1
		return ret

def main():
	S = input().rstrip()
	Q = int(input())
	queries = tuple((input().split() for _ in range(Q)))
	segfunc = lambda x, y: x | y
	seg = SegmentTree(S, segfunc)
	ans = []
	for (q_type, var1, var2) in queries:
		if q_type == '1':
			(idx, char) = (int(var1) - 1, var2)
			seg.update(idx, char)
		else:
			(left, right) = (int(var1) - 1, int(var2))
			x = seg.query(left, right)
			cnt = bin(x).count('1')
			ans.append(cnt)
	print('\n'.join(map(str, ans)))
main()


from sys import stdin

def main():
	(data, _) = (list(map(ord, input())), input())
	n = len(data) + 1
	sz = 1 << n.bit_length()
	cnt0 = [[0] * sz for _ in range(26)]
	cnt1 = [*[None] * 97, *cnt0]
	for (i, l) in enumerate(map(cnt1.__getitem__, data), 1):
		while i < sz:
			l[i] += 1
			i += i & -i
	data.insert(0, 0)
	for s in stdin.read().splitlines():
		if s[0] == '1':
			i = j = int(s[2:-2])
			c = ord(s[-1])
			if data[i] != c:
				l = cnt1[c]
				while j < sz:
					l[j] += 1
					j += j & -j
				(l, data[i]) = (cnt1[data[i]], c)
				while i < n:
					l[i] -= 1
					i += i & -i
		else:
			r = 0
			(lo, hi) = map(int, s[2:].split())
			lo -= 1
			for l in cnt0:
				(i, j, t) = (lo, hi, 0)
				while j:
					t += l[j]
					j -= j & -j
				while i:
					t -= l[i]
					i -= i & -i
				r += t > 0
			print(r)
main()


import sys, os, io
import math, bisect, operator
(inf, mod) = (float('inf'), 10 ** 9 + 7)
from itertools import groupby, accumulate
from heapq import heapify, heappop, heappush
from collections import deque, Counter, defaultdict
input = iter(sys.stdin.buffer.read().decode().splitlines()).__next__
Neo = lambda : list(map(int, input().split()))

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

def getsum(BIT, i):
	s = 0
	while i > 0:
		s += BIT[i]
		i -= i & -i
	return s
s = list(input())
LEN = len(s)
BIT = [[0] * (LEN + 1) for i in range(26)]
for i in range(len(s)):
	char = ord(s[i]) - 97
	update(BIT[char], LEN, i + 1, 1)
q = int(input())
for i in range(q):
	c = input().split()
	if c[0] == '1':
		char1 = ord(s[int(c[1]) - 1]) - 97
		s[int(c[1]) - 1] = c[2]
		update(BIT[char1], LEN, int(c[1]), -1)
		char2 = ord(c[2]) - 97
		update(BIT[char2], LEN, int(c[1]), 1)
	if c[0] == '2':
		l = int(c[1])
		r = int(c[2])
		p = 0
		for i in range(len(BIT)):
			p += min(1, getsum(BIT[i], r) - getsum(BIT[i], l - 1))
		print(p)


import os
import sys
from io import BytesIO, IOBase
from types import GeneratorType
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		import os
		self.os = os
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = self.os.read(self._fd, max(self.os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = self.os.read(self._fd, max(self.os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			self.os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
import time
start_time = time.time()
import collections as col
import math
from functools import reduce

def getInts():
	return [int(s) for s in input().split()]

def getInt():
	return int(input())

def getStrs():
	return [s for s in input().split()]

def getStr():
	return input()

def listStr():
	return list(input())

def solve():

	def build(arr):
		for i in range(n):
			x = ord(arr[i]) - ord('a')
			tree[n + i] = [0] * 26
			if 0 <= x <= 25:
				tree[n + i][x] = 1
		for i in range(n - 1, 0, -1):
			(a, b) = (tree[i << 1], tree[i << 1 | 1])
			tree[i] = [a[j] + b[j] for j in range(26)]

	def updateTreeNode(p, old_value, new_value):
		x = ord(old_value) - ord('a')
		y = ord(new_value) - ord('a')
		tree[p + n][x] = 0
		tree[p + n][y] = 1
		i = p + n
		while i > 1:
			i >>= 1
			(a, b) = (tree[i << 1], tree[i << 1 | 1])
			tree[i][x] = a[x] + b[x]
			tree[i][y] = a[y] + b[y]

	def query(l, r):
		res = [0] * 26
		l += n
		r += n
		while l < r:
			if l & 1:
				for j in range(26):
					res[j] += tree[l][j]
				l += 1
			if r & 1:
				r -= 1
				for j in range(26):
					res[j] += tree[r][j]
			l >>= 1
			r >>= 1
		res = [min(res[j], 1) for j in range(26)]
		return sum(res)
	S = listStr()
	n = len(S)
	q = getInt()
	tree = [''] * (2 * n)
	while len(S) < n:
		S.append('.')
	build(S)
	for qq in range(q):
		(A, B, C) = getStrs()
		A = int(A)
		B = int(B)
		B -= 1
		if A == 1:
			updateTreeNode(B, S[B], C)
			S[B] = C
		else:
			print(query(B, int(C)))
	return
solve()


import sys
import bisect
import heapq
Ri = lambda : [int(x) for x in sys.stdin.readline().split()]
ri = lambda : sys.stdin.readline().strip()

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

def list2d(a, b, c):
	return [[c] * b for i in range(a)]

def list3d(a, b, c, d):
	return [[[d] * c for j in range(b)] for i in range(a)]

def list4d(a, b, c, d, e):
	return [[[[e] * d for j in range(c)] for j in range(b)] for i in range(a)]

def ceil(x, y=1):
	return int(-(-x // y))

def INT():
	return int(input())

def MAP():
	return map(int, input().split())

def LIST(N=None):
	return list(MAP()) if N is None else [INT() for i in range(N)]

def Yes():
	print('Yes')

def No():
	print('No')

def YES():
	print('YES')

def NO():
	print('NO')
INF = 10 ** 18
MOD = 10 ** 9 + 7

def getsum(BITTree, i):
	s = 0
	i = i + 1
	while i > 0:
		s += BITTree[i]
		i -= i & -i
	return s

def updatebit(BITTree, n, i, v):
	i += 1
	while i <= n:
		BITTree[i] += v
		i += i & -i

def construct(arr, n):
	BITTree = [0] * (n + 1)
	for i in range(n):
		updatebit(BITTree, n, i, arr[i])
	return BITTree
s = ri()
n = len(s)
bit = list2d(26, n + 1, 0)
s = [i for i in s]
for i in range(len(s)):
	temp = ord(s[i]) - ord('a')
	updatebit(bit[temp], n, i, 1)
qq = int(ri())
for qqq in range(qq):
	q = ri().split()
	if q[0] == '2':
		q[1] = int(q[1])
		q[2] = int(q[2])
		ans = 0
		for i in range(26):
			ans += 1 if getsum(bit[i], q[2] - 1) - getsum(bit[i], q[1] - 2) > 0 else 0
		print(ans)
	else:
		q[1] = int(q[1])
		ind = ord(q[2]) - ord('a')
		ind1 = ord(s[q[1] - 1]) - ord('a')
		s[q[1] - 1] = q[2]
		updatebit(bit[ind1], n, q[1] - 1, -1)
		updatebit(bit[ind], n, q[1] - 1, 1)


import sys
input = sys.stdin.readline
base = ord('a')
s = list(input().strip())
n = len(s)
bit = [[0 for _ in range(n + 1)] for _ in range(26)]

def update(pos, index, value):
	index += 1
	while index <= n:
		bit[pos][index] += value
		index += index & -index

def querry(pos, index):
	ans = 0
	index += 1
	while index > 0:
		ans += bit[pos][index]
		index -= index & -index
	return ans
for (j, i) in enumerate(s):
	update(ord(i) - base, j, 1)
for _ in range(int(input())):
	(a, b, c) = input().split()
	if a == '1':
		index = int(b) - 1
		pos = ord(s[index]) - base
		update(pos, index, -1)
		s[index] = c
		pos = ord(c) - base
		update(pos, index, 1)
	else:
		ans = 0
		(l, r) = (int(b) - 1, int(c) - 1)
		for i in range(26):
			if querry(i, r) - querry(i, l - 1):
				ans += 1
		print(ans)


class SortedList:

	def __init__(self, iterable=[], _load=200):
		values = sorted(iterable)
		self._len = _len = len(values)
		self._load = _load
		self._lists = _lists = [values[i:i + _load] for i in range(0, _len, _load)]
		self._list_lens = [len(_list) for _list in _lists]
		self._mins = [_list[0] for _list in _lists]
		self._fen_tree = []
		self._rebuild = True

	def _fen_build(self):
		self._fen_tree[:] = self._list_lens
		_fen_tree = self._fen_tree
		for i in range(len(_fen_tree)):
			if i | i + 1 < len(_fen_tree):
				_fen_tree[i | i + 1] += _fen_tree[i]
		self._rebuild = False

	def _fen_update(self, index, value):
		if not self._rebuild:
			_fen_tree = self._fen_tree
			while index < len(_fen_tree):
				_fen_tree[index] += value
				index |= index + 1

	def _fen_query(self, end):
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		x = 0
		while end:
			x += _fen_tree[end - 1]
			end &= end - 1
		return x

	def _fen_findkth(self, k):
		_list_lens = self._list_lens
		if k < _list_lens[0]:
			return (0, k)
		if k >= self._len - _list_lens[-1]:
			return (len(_list_lens) - 1, k + _list_lens[-1] - self._len)
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		idx = -1
		for d in reversed(range(len(_fen_tree).bit_length())):
			right_idx = idx + (1 << d)
			if right_idx < len(_fen_tree) and k >= _fen_tree[right_idx]:
				idx = right_idx
				k -= _fen_tree[idx]
		return (idx + 1, k)

	def _delete(self, pos, idx):
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len -= 1
		self._fen_update(pos, -1)
		del _lists[pos][idx]
		_list_lens[pos] -= 1
		if _list_lens[pos]:
			_mins[pos] = _lists[pos][0]
		else:
			del _lists[pos]
			del _list_lens[pos]
			del _mins[pos]
			self._rebuild = True

	def _loc_left(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(lo, pos) = (-1, len(_lists) - 1)
		while lo + 1 < pos:
			mi = lo + pos >> 1
			if value <= _mins[mi]:
				pos = mi
			else:
				lo = mi
		if pos and value <= _lists[pos - 1][-1]:
			pos -= 1
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value <= _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def _loc_right(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(pos, hi) = (0, len(_lists))
		while pos + 1 < hi:
			mi = pos + hi >> 1
			if value < _mins[mi]:
				hi = mi
			else:
				pos = mi
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value < _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def add(self, value):
		_load = self._load
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len += 1
		if _lists:
			(pos, idx) = self._loc_right(value)
			self._fen_update(pos, 1)
			_list = _lists[pos]
			_list.insert(idx, value)
			_list_lens[pos] += 1
			_mins[pos] = _list[0]
			if _load + _load < len(_list):
				_lists.insert(pos + 1, _list[_load:])
				_list_lens.insert(pos + 1, len(_list) - _load)
				_mins.insert(pos + 1, _list[_load])
				_list_lens[pos] = _load
				del _list[_load:]
				self._rebuild = True
		else:
			_lists.append([value])
			_mins.append(value)
			_list_lens.append(1)
			self._rebuild = True

	def discard(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_right(value)
			if idx and _lists[pos][idx - 1] == value:
				self._delete(pos, idx - 1)

	def remove(self, value):
		_len = self._len
		self.discard(value)
		if _len == self._len:
			raise ValueError('{0!r} not in list'.format(value))

	def pop(self, index=-1):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		value = self._lists[pos][idx]
		self._delete(pos, idx)
		return value

	def bisect_left(self, value):
		(pos, idx) = self._loc_left(value)
		return self._fen_query(pos) + idx

	def bisect_right(self, value):
		(pos, idx) = self._loc_right(value)
		return self._fen_query(pos) + idx

	def count(self, value):
		return self.bisect_right(value) - self.bisect_left(value)

	def __len__(self):
		return self._len

	def __getitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		return self._lists[pos][idx]

	def __delitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		self._delete(pos, idx)

	def __contains__(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_left(value)
			return idx < len(_lists[pos]) and _lists[pos][idx] == value
		return False

	def __iter__(self):
		return (value for _list in self._lists for value in _list)

	def __reversed__(self):
		return (value for _list in reversed(self._lists) for value in reversed(_list))

	def __repr__(self):
		return 'SortedList({0})'.format(list(self))

class OrderedList(SortedList):

	def __init__(self, arg):
		super().__init__(arg)

	def rangeCountByValue(self, leftVal, rightVal):
		leftCummulative = self.bisect_left(leftVal)
		rightCummulative = self.bisect_left(rightVal + 1)
		return rightCummulative - leftCummulative

def charToInt(c):
	return ord(c) - ord('a')

def intToChar(x):
	return chr(ord('a') + x)

def main():
	s = input()
	n = len(s)
	arr = [charToInt(c) for c in s]
	olArr = [OrderedList([]) for _ in range(26)]
	for i in range(n):
		olArr[arr[i]].add(i)
	q = int(input())
	allans = []
	for _ in range(q):
		(typee, x, y) = input().split()
		if typee == '1':
			replaceIdx = int(x) - 1
			replaceChar = charToInt(y)
			prevChar = arr[replaceIdx]
			olArr[prevChar].remove(replaceIdx)
			olArr[replaceChar].add(replaceIdx)
			arr[replaceIdx] = replaceChar
		else:
			l = int(x) - 1
			r = int(y) - 1
			cnt = 0
			for i in range(26):
				left = olArr[i].bisect_left(l)
				right = olArr[i].bisect_right(r)
				if left < right:
					cnt += 1
			allans.append(cnt)
	multiLineArrayPrint(allans)
	return
import sys
input = lambda : sys.stdin.readline().rstrip('\r\n')

def oneLineArrayPrint(arr):
	print(' '.join([str(x) for x in arr]))

def multiLineArrayPrint(arr):
	print('\n'.join([str(x) for x in arr]))

def multiLineArrayOfArraysPrint(arr):
	print('\n'.join([' '.join([str(x) for x in y]) for y in arr]))

def readIntArr():
	return [int(x) for x in input().split()]

def makeArr(defaultValFactory, dimensionArr):
	dv = defaultValFactory
	da = dimensionArr
	if len(da) == 1:
		return [dv() for _ in range(da[0])]
	else:
		return [makeArr(dv, da[1:]) for _ in range(da[0])]

def queryInteractive(i, j):
	print('? {} {}'.format(i, j))
	sys.stdout.flush()
	return int(input())

def answerInteractive(ans):
	print('! {}'.format(' '.join([str(x) for x in ans])))
	sys.stdout.flush()
inf = float('inf')
MOD = 10 ** 9 + 7
for _abc in range(1):
	main()


import os
from io import BytesIO, IOBase
import sys
from collections import defaultdict, deque, Counter
from math import sqrt, pi, ceil, log, inf, gcd, floor
from itertools import combinations, permutations
from bisect import *
from fractions import Fraction
from heapq import *
from random import randint

class SortedList:

	def __init__(self, iterable=None, _load=200):
		if iterable is None:
			iterable = []
		values = sorted(iterable)
		self._len = _len = len(values)
		self._load = _load
		self._lists = _lists = [values[i:i + _load] for i in range(0, _len, _load)]
		self._list_lens = [len(_list) for _list in _lists]
		self._mins = [_list[0] for _list in _lists]
		self._fen_tree = []
		self._rebuild = True

	def _fen_build(self):
		self._fen_tree[:] = self._list_lens
		_fen_tree = self._fen_tree
		for i in range(len(_fen_tree)):
			if i | i + 1 < len(_fen_tree):
				_fen_tree[i | i + 1] += _fen_tree[i]
		self._rebuild = False

	def _fen_update(self, index, value):
		if not self._rebuild:
			_fen_tree = self._fen_tree
			while index < len(_fen_tree):
				_fen_tree[index] += value
				index |= index + 1

	def _fen_query(self, end):
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		x = 0
		while end:
			x += _fen_tree[end - 1]
			end &= end - 1
		return x

	def _fen_findkth(self, k):
		_list_lens = self._list_lens
		if k < _list_lens[0]:
			return (0, k)
		if k >= self._len - _list_lens[-1]:
			return (len(_list_lens) - 1, k + _list_lens[-1] - self._len)
		if self._rebuild:
			self._fen_build()
		_fen_tree = self._fen_tree
		idx = -1
		for d in reversed(range(len(_fen_tree).bit_length())):
			right_idx = idx + (1 << d)
			if right_idx < len(_fen_tree) and k >= _fen_tree[right_idx]:
				idx = right_idx
				k -= _fen_tree[idx]
		return (idx + 1, k)

	def _delete(self, pos, idx):
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len -= 1
		self._fen_update(pos, -1)
		del _lists[pos][idx]
		_list_lens[pos] -= 1
		if _list_lens[pos]:
			_mins[pos] = _lists[pos][0]
		else:
			del _lists[pos]
			del _list_lens[pos]
			del _mins[pos]
			self._rebuild = True

	def _loc_left(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(lo, pos) = (-1, len(_lists) - 1)
		while lo + 1 < pos:
			mi = lo + pos >> 1
			if value <= _mins[mi]:
				pos = mi
			else:
				lo = mi
		if pos and value <= _lists[pos - 1][-1]:
			pos -= 1
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value <= _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def _loc_right(self, value):
		if not self._len:
			return (0, 0)
		_lists = self._lists
		_mins = self._mins
		(pos, hi) = (0, len(_lists))
		while pos + 1 < hi:
			mi = pos + hi >> 1
			if value < _mins[mi]:
				hi = mi
			else:
				pos = mi
		_list = _lists[pos]
		(lo, idx) = (-1, len(_list))
		while lo + 1 < idx:
			mi = lo + idx >> 1
			if value < _list[mi]:
				idx = mi
			else:
				lo = mi
		return (pos, idx)

	def add(self, value):
		_load = self._load
		_lists = self._lists
		_mins = self._mins
		_list_lens = self._list_lens
		self._len += 1
		if _lists:
			(pos, idx) = self._loc_right(value)
			self._fen_update(pos, 1)
			_list = _lists[pos]
			_list.insert(idx, value)
			_list_lens[pos] += 1
			_mins[pos] = _list[0]
			if _load + _load < len(_list):
				_lists.insert(pos + 1, _list[_load:])
				_list_lens.insert(pos + 1, len(_list) - _load)
				_mins.insert(pos + 1, _list[_load])
				_list_lens[pos] = _load
				del _list[_load:]
				self._rebuild = True
		else:
			_lists.append([value])
			_mins.append(value)
			_list_lens.append(1)
			self._rebuild = True

	def discard(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_right(value)
			if idx and _lists[pos][idx - 1] == value:
				self._delete(pos, idx - 1)

	def remove(self, value):
		_len = self._len
		self.discard(value)
		if _len == self._len:
			raise ValueError('{0!r} not in list'.format(value))

	def pop(self, index=-1):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		value = self._lists[pos][idx]
		self._delete(pos, idx)
		return value

	def bisect_left(self, value):
		(pos, idx) = self._loc_left(value)
		return self._fen_query(pos) + idx

	def bisect_right(self, value):
		(pos, idx) = self._loc_right(value)
		return self._fen_query(pos) + idx

	def count(self, value):
		return self.bisect_right(value) - self.bisect_left(value)

	def __len__(self):
		return self._len

	def __getitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		return self._lists[pos][idx]

	def __delitem__(self, index):
		(pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
		self._delete(pos, idx)

	def __contains__(self, value):
		_lists = self._lists
		if _lists:
			(pos, idx) = self._loc_left(value)
			return idx < len(_lists[pos]) and _lists[pos][idx] == value
		return False

	def __iter__(self):
		return (value for _list in self._lists for value in _list)

	def __reversed__(self):
		return (value for _list in reversed(self._lists) for value in reversed(_list))

	def __repr__(self):
		return 'SortedList({0})'.format(list(self))

def main():
	s = list(map(lambda x: ord(x) - 97, input().rstrip()))
	n = len(s)
	q = int(input())
	a = [SortedList() for _ in range(26)]
	for i in range(n):
		a[s[i]].add(i + 1)
	for i in range(q):
		x = input().split()
		if x[0] == '1':
			z = int(x[1])
			a[s[z - 1]].remove(z)
			y = ord(x[2]) - 97
			s[z - 1] = y
			a[y].add(z)
		else:
			(l, r) = (int(x[1]), int(x[2]))
			su = 0
			for j in range(26):
				xx = len(a[j])
				if xx:
					y = a[j].bisect_left(l)
					if y != xx and a[j][y] <= r:
						su += 1
			print(su)
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


from sys import stdin, stdout
g = stdin.readline

def f(j):
	p = k[j][:]
	while j:
		j -= j & -j
		for i in range(26):
			p[i] += k[j][i]
	return p
a = ord('a')
s = [ord(q) - a for q in g()[:-1]]
m = int(g())
n = len(s) + 1
k = [[0] * 26 for i in range(n)]
for (j, v) in enumerate(s, 1):
	while j < n:
		k[j][v] += 1
		j += j & -j
for i in range(m):
	(t, x, y) = g().split()
	if t == '1':
		(j, u) = (int(x), ord(y) - a)
		(v, s[j - 1]) = (s[j - 1], u)
		while j < n:
			k[j][u] += 1
			k[j][v] -= 1
			j += j & -j
	else:
		l = f(int(x) - 1)
		r = f(int(y))
		d = sum((v > u for (u, v) in zip(l, r)))
		stdout.write(str(d) + '\n')


from sys import stdin, stdout
from operator import or_

class Seg_Tree:

	def __init__(self, arr, fun):
		self.fun = fun
		self.n = 1 << len(arr).bit_length()
		self.seg_t = [0 for i in range(self.n * 2)]
		for (i, v) in enumerate(arr):
			self.seg_t[i + self.n] = 1 << ord(v) - 97
		for i in range(self.n - 1, 0, -1):
			self.seg_t[i] = fun(self.seg_t[i << 1], self.seg_t[i << 1 | 1])
	__slots__ = ['fun', 'n', 'seg_t']

	def query(self, qlow, qhigh, low, high, pos):
		if qlow == low and qhigh == high:
			return self.seg_t[pos]
		mid = (low + high) // 2
		if qlow >= low and qhigh <= mid:
			return self.query(qlow, qhigh, low, mid, pos * 2)
		elif qlow > mid and qhigh <= high:
			return self.query(qlow, qhigh, mid + 1, high, pos * 2 + 1)
		else:
			return self.fun(self.query(qlow, mid, low, mid, pos * 2), self.query(mid + 1, qhigh, mid + 1, high, pos * 2 + 1))

	def update(self, pos, value):
		self.seg_t[pos + self.n - 1] = 1 << ord(value) - 97
		i = pos + self.n - 1
		while i > 1:
			self.seg_t[i >> 1] = self.fun(self.seg_t[i], self.seg_t[i ^ 1])
			i >>= 1

def main():
	input = stdin.readline
	arr = input().rstrip()
	t = int(input())
	out = []
	s = Seg_Tree(arr, or_)
	for i in range(t):
		(m, a, b) = input().split()
		a = int(a)
		if m == '2':
			b = int(b)
			x = s.query(a, b, 1, s.n, 1)
			out.append(bin(x)[2:].count('1'))
		else:
			s.update(a, b)
	stdout.write('\n'.join(map(str, out)))
main()


import atexit
import io
import sys
_INPUT_LINES = sys.stdin.read().splitlines()
input = iter(_INPUT_LINES).__next__
_OUTPUT_BUFFER = io.StringIO()
sys.stdout = _OUTPUT_BUFFER

@atexit.register
def write():
	sys.__stdout__.write(_OUTPUT_BUFFER.getvalue())

class SegTree:
	N = 100002

	def __init__(self):
		self.tree = [0] * (2 * self.N)

	def build(self, arr):
		for i in range(n):
			self.tree[n + i] = arr[i]
		for i in range(n - 1, 0, -1):
			self.tree[i] = self.tree[i << 1] + self.tree[i << 1 | 1]

	def update_tree_node(self, p, value):
		self.tree[p + n] = value
		p = p + n
		i = p
		while i > 1:
			self.tree[i >> 1] = self.tree[i] + self.tree[i ^ 1]
			i >>= 1

	def query(self, l, r):
		res = 0
		l += n
		r += n
		while l < r:
			if l & 1:
				res += self.tree[l]
				l += 1
			if r & 1:
				r -= 1
				res += self.tree[r]
			l >>= 1
			r >>= 1
		return res
s = list(input())
n = len(s)
trees = []
for i in range(26):
	trees.append(SegTree())
	trees[-1].build([0] * n)
for (idx, c) in enumerate(s):
	trees[ord(c) - ord('a')].update_tree_node(idx, 1)
t = int(input())
for _ in range(t):
	(q, p1, p2) = input().split()
	(q, p1) = (int(q), int(p1) - 1)
	if q == 1:
		trees[ord(s[p1]) - ord('a')].update_tree_node(p1, 0)
		trees[ord(p2) - ord('a')].update_tree_node(p1, 1)
		s[p1] = p2
	else:
		p2 = int(p2) - 1
		ans = 0
		for seg in trees:
			if seg.query(p1, p2 + 1) != 0:
				ans += 1
		print(ans)


import sys

def count_set_bits(i):
	count = 0
	while i:
		count += i & 1
		i >>= 1
	return count

class SegmentTree:

	def __init__(self, src):
		i_a = ord('a')
		source = [1 << ord(c) - i_a for c in src]
		self.n = 1 << (len(source) - 1).bit_length()
		self.data = [0] * self.n + source + [0] * (self.n - len(source))
		self.__build()

	def __build(self):
		for i in range(self.n - 1, -1, -1):
			self.data[i] = self.data[2 * i] | self.data[2 * i + 1]

	def update(self, pos, c):
		pos += self.n
		self.data[pos] = 1 << ord(c) - ord('a')
		while pos > 1:
			pos >>= 1
			self.data[pos] = self.data[2 * pos + 1] | self.data[2 * pos]

	def count_unique(self, left, right):
		left += self.n
		right += self.n
		res = self.data[left] | self.data[right]
		while left < right - 1:
			if not left & 1:
				res |= self.data[left + 1]
			if right & 1:
				res |= self.data[right - 1]
			left >>= 1
			right >>= 1
		return count_set_bits(res)
(s, _) = (input(), input())
result = []
tree = SegmentTree(s)
for r in sys.stdin.read().splitlines():
	(com, a, b) = r.split()
	if com == '1':
		tree.update(int(a) - 1, b)
	else:
		print(tree.count_unique(int(a) - 1, int(b) - 1))


import sys
input = sys.stdin.readline

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

def getsum(BIT, i):
	s = 0
	while i > 0:
		s += BIT[i]
		i -= i & -i
	return s
s = [i for i in input() if i != '\n']
LEN = len(s)
BIT = [[0] * (LEN + 1) for i in range(26)]
for i in range(len(s)):
	char = ord(s[i]) - 97
	update(BIT[char], LEN, i + 1, 1)
q = int(input())
for i in range(q):
	c = [i for i in input().split()]
	if c[0] == '1':
		char1 = ord(s[int(c[1]) - 1]) - 97
		s[int(c[1]) - 1] = c[2]
		update(BIT[char1], LEN, int(c[1]), -1)
		char2 = ord(c[2]) - 97
		update(BIT[char2], LEN, int(c[1]), 1)
	if c[0] == '2':
		l = int(c[1])
		r = int(c[2])
		p = 0
		for i in range(len(BIT)):
			p += min(1, getsum(BIT[i], r) - getsum(BIT[i], l - 1))
		print(p)


from collections import *

class segmenttree:

	def __init__(self, arr, n, ch):
		(self.tree, self.n) = ([0] * (2 * n), n)
		if arr:
			for i in range(2 * n - 1, 0, -1):
				if i >= n:
					if arr[i - n] == ch:
						self.tree[i] = 1
				else:
					self.tree[i] = self.tree[i << 1] + self.tree[(i << 1) + 1]

	def query(self, l, r):
		res = 0
		l += self.n
		r += self.n
		while l < r:
			if l & 1:
				res += self.tree[l]
				l += 1
			if r & 1:
				r -= 1
				res += self.tree[r]
			l >>= 1
			r >>= 1
		return res

	def update(self, ix, val):
		ix += self.n
		self.tree[ix] = val
		while ix > 1:
			self.tree[ix >> 1] = self.tree[ix] + self.tree[ix ^ 1]
			ix >>= 1

	def insert(self, x):
		self.update(x - 1, 1)

	def delete(self, x):
		self.update(x - 1, 0)
s = list(input())
seg = [segmenttree(s, len(s), chr(ord('a') + i)) for i in range(26)]
ans = []
for i in range(int(input())):
	(a, b, c) = input().split()
	(a, b) = (int(a), int(b))
	if a == 1:
		seg[ord(s[b - 1]) - ord('a')].delete(b)
		seg[ord(c) - ord('a')].insert(b)
		s[b - 1] = c
	else:
		tem = 0
		for i in range(26):
			if seg[i].query(b - 1, int(c)) > 0:
				tem += 1
		ans.append(str(tem))
print('\n'.join(ans))


import math
import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

class SegmentTree:

	def __init__(self, data, default=0, func=lambda a, b: a | b):
		self._default = default
		self._func = func
		self._len = len(data)
		self._size = _size = 1 << (self._len - 1).bit_length()
		self.data = [default] * (2 * _size)
		self.data[_size:_size + self._len] = data
		for i in reversed(range(_size)):
			self.data[i] = func(self.data[i + i], self.data[i + i + 1])

	def __delitem__(self, idx):
		self[idx] = self._default

	def __getitem__(self, idx):
		return self.data[idx + self._size]

	def __setitem__(self, idx, value):
		idx += self._size
		self.data[idx] = value
		idx >>= 1
		while idx:
			self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1])
			idx >>= 1

	def __len__(self):
		return self._len

	def query(self, start, stop):
		if start == stop:
			return self.__getitem__(start)
		stop += 1
		start += self._size
		stop += self._size
		res = self._default
		while start < stop:
			if start & 1:
				res = self._func(res, self.data[start])
				start += 1
			if stop & 1:
				stop -= 1
				res = self._func(res, self.data[stop])
			start >>= 1
			stop >>= 1
		return res

	def __repr__(self):
		return 'SegmentTree({0})'.format(self.data)
s = input()
l = [0] * len(s)
for i in range(len(s)):
	e = ord(s[i]) - 97
	l[i] = 2 ** e
s = SegmentTree(l)
q = int(input())
for i in range(q):
	(a, b, c) = map(str, input().split())
	if a == '1':
		idx = int(b)
		value = c
		s.__setitem__(idx - 1, 2 ** (ord(value) - 97))
	else:
		b = int(b)
		c = int(c)
		e = s.query(b - 1, c - 1)
		e = bin(e).replace('0b', '')
		print(e.count('1'))


from sys import stdin, stdout
R = lambda : map(int, input().split())
S = list(stdin.readline().strip())
Q = int(input())
n = len(S)
S = list(S)
sum_array = [[0] * (n + 1) for _ in range(26)]

def lowbit(x):
	return x & -x

def add(x, val, idx):
	while x <= n:
		sum_array[idx][x] += val
		x += lowbit(x)

def sum(x, idx):
	res = 0
	while x > 0:
		res += sum_array[idx][x]
		x -= lowbit(x)
	return res
for i in range(n):
	idx = ord(S[i]) - 97
	add(i + 1, 1, idx)
for _ in range(Q):
	A = stdin.readline().split()
	(a, b, c) = (int(A[0]), int(A[1]), A[2])
	if a == 1:
		pre = ord(S[b - 1]) - 97
		cur = ord(c) - 97
		S[b - 1] = c
		add(b, -1, pre)
		add(b, 1, cur)
	else:
		c = int(c)
		if c - b == 0:
			print(1)
		else:
			res = 0
			for i in range(26):
				diff = sum(c, i) - sum(b - 1, i)
				res += int(diff > 0)
			print(res)


from operator import or_
from typing import Callable, List, Sequence, Union, Optional

class SegmentTree:
	__slots__ = ['_default_value', '_seg_func', '_modifying_func', '_size', '_tree']

	def __init__(self, initial_values: Sequence, default_value: Union[int, str], seg_func: Callable, modifying_func: Optional[Callable]=None) -> None:
		self._default_value = default_value
		self._seg_func = seg_func
		self._modifying_func = modifying_func
		self._size = 1 << (len(initial_values) - 1).bit_length()
		self._tree = self._build(initial_values)

	def _build(self, initial_values: Sequence) -> List:
		tree = [self._default_value] * (2 * self._size)
		if self._modifying_func:
			initial_values = list(map(self._modifying_func, initial_values))
		for (idx, val) in enumerate(initial_values):
			tree[idx + self._size - 1] = val
		for idx in range(self._size - 2, -1, -1):
			tree[idx] = self._seg_func(tree[2 * idx + 1], tree[2 * idx + 2])
		return tree

	def update(self, index: int, value: int) -> None:
		index += self._size - 1
		if self._modifying_func:
			value = self._modifying_func(value)
		self._tree[index] = value
		while index:
			index = (index - 1) // 2
			self._tree[index] = self._seg_func(self._tree[2 * index + 1], self._tree[2 * index + 2])

	def query(self, left: int, right: int) -> Union[int, str]:
		left += self._size
		right += self._size
		result = self._default_value
		while left < right:
			if left & 1:
				result = self._seg_func(result, self._tree[left - 1])
				left += 1
			if right & 1:
				right -= 1
				result = self._seg_func(result, self._tree[right - 1])
			left >>= 1
			right >>= 1
		return result

def main():
	(S, _, *queries) = open(0).read().split()
	tree = SegmentTree(S, 0, or_, lambda s: 1 << ord(s) - 97)
	ans = []
	for (q_type, var1, var2) in zip(*[iter(queries)] * 3):
		if q_type == '1':
			(idx, char) = (int(var1) - 1, var2)
			tree.update(idx, char)
		else:
			(left, right) = (int(var1) - 1, int(var2))
			x = tree.query(left, right)
			cnt = bin(x).count('1')
			ans.append(cnt)
	print('\n'.join(map(str, ans)))
main()


from sys import stdin, stdout
from math import ceil
from operator import or_

class Seg_Tree:

	def __init__(self, arr, fun):
		self.fun = fun
		self.n = 1 << len(arr).bit_length()
		tree = [0 for i in range(self.n * 2)]
		self.tree = tree
		local_ord = ord
		for (i, v) in enumerate(arr):
			tree[i + self.n] = 1 << local_ord(v) - 97
		for i in range(self.n - 1, 0, -1):
			tree[i] = fun(tree[i << 1], tree[i << 1 | 1])
	__slots__ = ['fun', 'n', 'tree']

	def query(self, qlow, qhigh):
		left = qlow + self.n
		right = qhigh + self.n
		res = 0
		while left <= right:
			if not left & 1:
				res = self.fun(res, self.tree[left - 1])
				left += 1
			if right & 1:
				res = self.fun(res, self.tree[right - 1])
				right = right - 1
			left = ceil(left / 2)
			right = ceil(right / 2)
		return res

	def update(self, pos, value):
		self.tree[pos + self.n - 1] = 1 << ord(value) - 97
		i = pos + self.n - 1
		while i > 1:
			self.tree[i >> 1] = self.fun(self.tree[i], self.tree[i ^ 1])
			i >>= 1

def main():
	input = stdin.readline
	arr = input().rstrip()
	t = int(input())
	out = []
	s = Seg_Tree(arr, or_)
	for i in range(t):
		(m, a, b) = input().split()
		a = int(a)
		if m == '2':
			b = int(b)
			x = s.query(a, b)
			out.append(bin(x)[2:].count('1'))
		else:
			s.update(a, b)
	stdout.write('\n'.join(map(str, out)))
main()


d = dict()
for i in 'abcdefghijklmnopqrstuvwxyz':
	yoyo = ['0'] * 26
	yoyo[ord(i) - ord('a')] = '1'
	yoyo = yoyo[::-1]
	d[i] = int(''.join(yoyo), 2)

def get(l, r, a):
	n = len(a) // 2
	l += n - 1
	r += n
	k = 0
	while l < r:
		if l % 2 == 1:
			k |= a[l]
			l += 1
		if r % 2 == 1:
			k |= a[r - 1]
			r -= 1
		l //= 2
		r //= 2
	c = 0
	while k > 0:
		k &= k - 1
		c += 1
	return c

def update(l, r, lol):
	l += len(lol) // 2
	l -= 1
	lol[l] = d[r]
	i = l // 2
	while i > 0:
		lol[i] = lol[2 * i] | lol[2 * i + 1]
		i //= 2
a = list(input())
m = len(a)
lol = [0] * (m * 2)
i = 2 * m - 1
while i > 0:
	if i >= m:
		lol[i] = d[a[i - m]]
	else:
		lol[i] = lol[2 * i] | lol[2 * i + 1]
	i -= 1
n = int(input())
for __ in range(n):
	(x, y, z) = input().split()
	x = int(x)
	y = int(y)
	if x == 1:
		update(y, z, lol)
	else:
		z = int(z)
		print(get(y, z, lol))


import sys
sys.setrecursionlimit(10000000)

def input():
	return sys.stdin.readline()[:-1]
from bisect import *
from collections import *
from heapq import *
import itertools
import math
INF = 10 ** 9
MOD = 10 ** 9 + 7

class BIT:

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

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

	def sum(self, x):
		ret = 0
		while x != 0:
			ret += self.bit[x]
			x -= x & -x
		return ret
atoz = [chr(i) for i in range(97, 97 + 26)]
dic = defaultdict(int)
for (i, c) in enumerate(atoz):
	dic[c] = i
s = [dic[c] for c in input()]
Q = int(input())
bits = [BIT(len(s) + 1) for i in range(26)]
for (i, x) in enumerate(s, 1):
	bits[x].add(i, 1)
for _ in range(Q):
	(q, i, j) = input().split()
	(q, i) = (int(q), int(i))
	if q == 1:
		bits[s[i - 1]].add(i, -1)
		bits[dic[j]].add(i, 1)
		s[i - 1] = dic[j]
	else:
		cnt = 0
		for bit in bits:
			cnt += bit.sum(int(j)) - bit.sum(i - 1) > 0
		print(cnt)


class SegmentTree:

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

	def set(self, idx, x):
		x_val = ord(x) - 97
		self.tree[idx + self.size - 1] = 1 << x_val

	def build(self):
		for i in range(self.size - 2, -1, -1):
			self.tree[i] = self.tree[i * 2 + 1] | self.tree[i * 2 + 2]

	def update(self, idx, x):
		idx += self.size - 1
		x_val = ord(x) - 97
		self.tree[idx] = 1 << x_val
		while idx > 0:
			idx = (idx - 1) // 2
			self.tree[idx] = self.tree[idx * 2 + 1] | self.tree[idx * 2 + 2]

	def query(self, l, r):
		(res, l, r) = (0, l + self.size, r + self.size)
		while l < r:
			if l & 1:
				res |= self.tree[l - 1]
				l += 1
			if r & 1:
				r -= 1
				res |= self.tree[r - 1]
			l >>= 1
			r >>= 1
		return res
s = input()
n = int(input())
queries = tuple((input().split() for _ in range(n)))
st = SegmentTree(len(s))
for (i, c) in enumerate(s):
	st.set(i, c)
st.build()
for (a, b, c) in queries:
	if a == '1':
		st.update(int(b) - 1, c)
	else:
		q = st.query(int(b) - 1, int(c))
		print(bin(q).count('1'))


from sys import stdin
input = stdin.readline

class BIT:

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

	def sum(self, i):
		ans = [0] * 26
		i += 1
		while i > 0:
			for j in range(26):
				ans[j] += self.tree[i][j]
			i -= i & -i
		return ans

	def update(self, i, ch, value):
		i += 1
		while i <= self.n:
			self.tree[i][ch] += value
			i += i & -i

def f(s, q):
	s = list(s)
	cnt = [[0] * 26 for i in range(len(s))]
	ft = BIT(len(s))
	for i in range(len(s)):
		ft.update(i, ord(s[i]) - ord('a'), 1)
	for (t, l, r) in q:
		if t == '2':
			l = int(l) - 1
			if l == 0:
				lr = [0] * 26
			else:
				lr = ft.sum(l - 1)
			rr = ft.sum(int(r) - 1)
			li = list(map(lambda x, y: abs(x - y), lr, rr))
			print(26 - li.count(0))
		if t == '1':
			l = int(l) - 1
			cur = ord(s[l]) - ord('a')
			new = ord(r) - ord('a')
			ft.update(l, cur, -1)
			ft.update(l, new, 1)
			s[l] = r
s = input().strip()
q = []
for i in range(int(input())):
	(t, l, r) = map(str, input().strip().split())
	q.append((t, l, r))
f(s, q)


from sys import stdin, stdout

def update1(idx, value, prefix):
	while idx < n + 1:
		prefix[idx][p[value]] += 1
		idx += idx & -1 * idx

def update(idx, value, org, prefix):
	while idx < n + 1:
		prefix[idx][p[value]] += 1
		prefix[idx][p[org]] -= 1
		idx += idx & -1 * idx

def query(idx):
	ans = [0] * 26
	for i in range(26):
		ans[i] += prefix[idx][i]
	while idx != 0:
		idx -= idx & -1 * idx
		for i in range(26):
			ans[i] += prefix[idx][i]
	return ans
s = stdin.readline().rstrip()
s = [i for i in s]
j = 0
p = dict()
n = len(s)
for i in range(97, 123):
	p[chr(i)] = j
	j += 1
q = int(stdin.readline())
prefix = [[0] * 26 for i in range(n + 1)]
for i in range(n):
	update1(i + 1, s[i], prefix)
for i in range(q):
	a = stdin.readline().split()
	if a[0] == '1':
		update(int(a[1]), a[2], s[int(a[1]) - 1], prefix)
		s[int(a[1]) - 1] = a[2]
	else:
		ans1 = query(int(a[1]) - 1)
		ans2 = query(int(a[2]))
		for i in range(26):
			ans2[i] -= ans1[i]
		y = 0
		for i in ans2:
			if i > 0:
				y += 1
		stdout.write(str(y))
		stdout.write('\n')


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

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

def getvalue(v, moji):
	ANS = 0
	while v != 0:
		ANS += BIT[moji][v]
		v -= v & -v
	return ANS
for i in range(len(S)):
	x = ord(S[i]) - 97
	update(i + 1, 1, x)
for testcases in range(q):
	A = input().split()
	if A[0] == '1':
		motoban = int(A[1]) - 1
		motochr = ord(S2[motoban]) - 97
		update(motoban + 1, -1, motochr)
		nowchr = ord(A[2]) - 97
		update(motoban + 1, 1, nowchr)
		S2[motoban] = A[2]
	else:
		score = 0
		l = int(A[1])
		r = int(A[2])
		for i in range(26):
			if getvalue(r, i) - getvalue(l - 1, i) >= 1:
				score += 1
		print(score)


from string import ascii_lowercase
from sys import stdin

class Node:
	__slots__ = ('left', 'right', 'key', 'priority')

	def __init__(self, key, priority, left=None, right=None):
		self.left = left
		self.right = right
		self.key = key
		self.priority = priority

	def __str__(self):
		return f'{self.key}<{self.priority}> (left: {self.left}, right: {self.right})'

	def __repr__(self):
		return str(self)

	def __eq__(self, other):
		if other is not None and self.key == other.key and (self.priority == other.priority):
			return self.left == other.left and self.right == other.right
		return False

	def copy(self):
		return Node(key=self.key, priority=self.priority, left=self.left.copy() if self.left is not None else None, right=self.right.copy() if self.right is not None else None)

	def __iter__(self):
		if self.left is not None:
			yield from self.left
		yield self.key
		if self.right is not None:
			yield from self.right

	def depth(self):
		ld = 0
		if self.left:
			ld = self.left.depth()
		rd = 0
		if self.right:
			rd = self.right.depth()
		return max(ld, rd) + 1

class Treap:
	__slots__ = ('root', '_max_p', '_last', '_p', '_d')

	def __init__(self):
		self.root = None
		self._max_p = 2 ** 64 - 1
		self._last = 1
		self._p = 2 ** 65 - 49
		self._d = self._p // 7

	def _split(self, node, key):
		lesser = None
		rest = None
		lesser_node = None
		rest_node = None
		to_split = node
		while to_split is not None:
			if to_split.key < key:
				(to_lesser, to_split) = (to_split, to_split.right)
				to_lesser.right = None
				if lesser_node is None:
					lesser = to_lesser
				else:
					lesser_node.right = to_lesser
				lesser_node = to_lesser
			else:
				(to_split, to_rest) = (to_split.left, to_split)
				to_rest.left = None
				if rest_node is None:
					rest = to_rest
				else:
					rest_node.left = to_rest
				rest_node = to_rest
		return (lesser, rest)

	def _merge(self, lesser, greater):
		result = None
		current_node = None
		while lesser is not None or greater is not None:
			if lesser is None:
				add_to_tree = greater
				greater = None
			elif greater is None:
				add_to_tree = lesser
				lesser = None
			elif lesser.priority <= greater.priority:
				add_to_tree = greater
				greater = greater.left
				add_to_tree.left = None
			else:
				add_to_tree = lesser
				lesser = lesser.right
				add_to_tree.right = None
			if result is None:
				result = add_to_tree
			elif current_node.key > add_to_tree.key:
				current_node.left = add_to_tree
			else:
				current_node.right = add_to_tree
			current_node = add_to_tree
		return result

	def __contains__(self, key):
		current_node = self.root
		while current_node is not None:
			if current_node.key < key:
				current_node = current_node.right
			elif current_node.key > key:
				current_node = current_node.left
			else:
				break
		return current_node is not None

	def insert(self, key):
		if key in self:
			return False
		self._insert(key)
		return True

	def _insert(self, key):
		priority = self._get_priority()
		parent = None
		current_node = self.root
		while current_node is not None and current_node.priority >= priority:
			parent = current_node
			if current_node.key < key:
				current_node = current_node.right
			else:
				current_node = current_node.left
		new_node = Node(key=key, priority=priority)
		if current_node is not None:
			(new_node.left, new_node.right) = self._split(current_node, key)
		if parent is None:
			self.root = new_node
		elif parent.key > key:
			parent.left = new_node
		else:
			parent.right = new_node

	def _get_priority(self):
		p = self._last * self._d % self._p
		self._last = p
		return p

	def remove(self, key):
		if self.root is None or key not in self:
			return False
		else:
			self.root = self._remove(self.root, key)
			return True

	def successor(self, key):
		if self.root is None:
			return None
		return self._successor(self.root, key)

	def _successor(self, root, key):
		found = None
		while root is not None:
			if root.key > key:
				if found is None:
					found = root.key
				elif root.key < found:
					found = root.key
				root = root.left
			else:
				root = root.right
		return found

	def _remove(self, root, key, _parent=None, _where=None):
		parent = None
		current_node = root
		while current_node.key != key:
			parent = current_node
			if current_node.key < key:
				current_node = current_node.right
			else:
				current_node = current_node.left
		merged = self._merge(current_node.left, current_node.right)
		if parent is None:
			return merged
		elif merged is None:
			if parent.key < key:
				parent.right = None
			else:
				parent.left = None
			return root
		else:
			if parent.key > merged.key:
				parent.left = merged
			else:
				parent.right = merged
			return root

	def __iter__(self):
		if self.root is not None:
			yield from self.root

	def depth(self):
		if self.root is None:
			return 0
		else:
			return self.root.depth()
treaps = {c: Treap() for c in ascii_lowercase}
letters = list(stdin.readline().strip())
for (index, letter) in enumerate(letters):
	treaps[letter].insert(index)
q = int(input())
for _ in range(q):
	(query, a, b) = stdin.readline().split()
	if query == '1':
		index = int(a) - 1
		old_c = letters[index]
		treaps[old_c].remove(index)
		treaps[b].insert(index)
		letters[index] = b
	else:
		start = int(a) - 1
		stop = int(b)
		counter = 0
		for c in ascii_lowercase:
			next_index = treaps[c].successor(start - 1)
			if next_index is None:
				continue
			if start <= next_index < stop:
				counter += 1
		print(counter)


import sys
import math
try:
	sys.stdin = open('input.txt', 'r')
	sys.stdout = open('output.txt', 'w')
except:
	input = sys.stdin.readline
s = input().strip()
n = len(s)
s = [0] + list(s)
BIT = [[0] * (n + 1) for i in range(26)]

def takeInput():
	return [int(x) for x in input().strip().split()]

def update(treeIndex, pos, val, n):
	tree = BIT[treeIndex]
	while pos <= n:
		tree[pos] += val
		pos += pos & -pos

def query(treeIndex, pos):
	ans = 0
	tree = BIT[treeIndex]
	while pos > 0:
		ans += tree[pos]
		pos -= pos & -pos
	return ans

def rangeQuery(treeIndex, left, right):
	return query(treeIndex, right) - query(treeIndex, left - 1)

def getTreeIndex(c):
	return ord(c) - 97
q = int(input())
for i in range(1, n + 1):
	index = getTreeIndex(s[i])
	update(index, i, 1, n)
for q_i in range(q):
	temp = [x for x in input().split()]
	if temp[0] == '1':
		pos = int(temp[1])
		currentChar = s[pos]
		current_index = getTreeIndex(currentChar)
		update(current_index, pos, -1, n)
		newChar = temp[2]
		s[pos] = newChar
		new_index = getTreeIndex(newChar)
		update(new_index, pos, 1, n)
	else:
		l = int(temp[1])
		r = int(temp[2])
		ans = 0
		for index in range(0, 26):
			count = rangeQuery(index, l, r)
			if count > 0:
				ans += 1
		print(ans)


from math import log2

class SegmentTree:

	def __init__(self, array, func=lambda a, b: a | b):
		self.n = len(array)
		self.size = 2 ** (int(log2(self.n - 1)) + 1) if self.n != 1 else 1
		self.func = func
		self.default = 0
		self.data = [self.default] * (2 * self.size)
		self.process(array)

	def process(self, array):
		self.data[self.size:self.size + self.n] = array
		for i in range(self.size - 1, -1, -1):
			self.data[i] = self.func(self.data[2 * i], self.data[2 * i + 1])

	def query(self, alpha, omega):
		if alpha == omega:
			return self.data[alpha + self.size]
		res = self.default
		alpha += self.size
		omega += self.size + 1
		while alpha < omega:
			if alpha & 1:
				res = self.func(res, self.data[alpha])
				alpha += 1
			if omega & 1:
				omega -= 1
				res = self.func(res, self.data[omega])
			alpha >>= 1
			omega >>= 1
		return res

	def update(self, index, value):
		index += self.size
		self.data[index] = value
		index >>= 1
		while index:
			self.data[index] = self.func(self.data[2 * index], self.data[2 * index + 1])
			index >>= 1
store = ['0' for s in range(26)]
nums = []
for s in range(26):
	newy = store.copy()
	newy[s] = '1'
	binrep = ''.join(newy)
	int1 = int(binrep, 2)
	nums.append(int1)
string1 = [nums[ord(k) - 97] for k in input()]
segtree = SegmentTree(string1)
for j in range(int(input())):
	val = list(input().split())
	if val[0] == '1':
		ind = int(val[1]) - 1
		v0 = ord(val[2]) - 97
		segtree.update(ind, nums[v0])
	else:
		ind1 = int(val[1]) - 1
		ind2 = int(val[2]) - 1
		ans = bin(segtree.query(ind1, ind2)).count('1')
		print(ans)


import sys
input = sys.stdin.readline
S = list(input().rstrip())
L = len(S)
Q = int(input())
data = []
for _ in range(Q):
	A = list(map(str, input().split()))
	data.append(A)
alp = [chr(i) for i in range(97, 97 + 26)]
BITs = {}
for a in alp:
	BITs[a] = [0] * (L + 1)

def query_sum(i, al):
	s = 0
	while i > 0:
		s += BITs[al][i]
		i -= i & -i
	return s

def add(i, x, al):
	while i <= L:
		BITs[al][i] += x
		i += i & -i

def main():
	for (i, s) in enumerate(S):
		add(i + 1, 1, s)
	for A in data:
		if A[0] == '1':
			(l, s) = (int(A[1]), A[2])
			for al in alp:
				if query_sum(l, al) - query_sum(l - 1, al) == 1:
					add(l, -1, al)
					break
			add(l, 1, s)
		else:
			(l, r) = (int(A[1]), int(A[2]))
			c = 0
			for al in alp:
				if query_sum(r, al) - query_sum(l - 1, al) > 0:
					c += 1
			print(c)

def __starting_point():
	main()
__starting_point()


class SegmentTree:

	def __init__(self, data, default=0, func=max):
		self._default = default
		self._func = func
		self._len = len(data)
		self._size = _size = 1 << (self._len - 1).bit_length()
		self.data = [default] * (2 * _size)
		self.data[_size:_size + self._len] = data
		for i in reversed(range(_size)):
			self.data[i] = func(self.data[i + i], self.data[i + i + 1])

	def __delitem__(self, idx):
		self[idx] = self._default

	def __getitem__(self, idx):
		return self.data[idx + self._size]

	def __setitem__(self, idx, value):
		idx += self._size
		self.data[idx] = value
		idx >>= 1
		while idx:
			self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1])
			idx >>= 1

	def __len__(self):
		return self._len

	def query(self, start, stop):
		if start == stop:
			return self.__getitem__(start)
		stop += 1
		start += self._size
		stop += self._size
		res = self._default
		while start < stop:
			if start & 1:
				res = self._func(res, self.data[start])
				start += 1
			if stop & 1:
				stop -= 1
				res = self._func(res, self.data[stop])
			start >>= 1
			stop >>= 1
		return res

	def __repr__(self):
		return 'SegmentTree({0})'.format(self.data)
s = input()
a = []
for i in s:
	a += [2 ** (ord(i) - 97)]
st = SegmentTree(a, func=lambda x, y: x | y)
for _ in range(int(input())):
	(p, q, r) = input().split()
	if p == '1':
		st.__setitem__(int(q) - 1, 2 ** (ord(r) - 97))
	else:
		result = st.query(int(q) - 1, int(r) - 1)
		print(bin(result)[2:].count('1'))


import os
import sys
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
from math import log2

class SegmentTree:

	def __init__(self, array, func=lambda a, b: a | b):
		self.n = len(array)
		self.size = 2 ** (int(log2(self.n - 1)) + 1) if self.n != 1 else 1
		self.func = func
		self.default = 0
		self.data = [self.default] * (2 * self.size)
		self.process(array)

	def process(self, array):
		self.data[self.size:self.size + self.n] = array
		for i in range(self.size - 1, -1, -1):
			self.data[i] = self.func(self.data[2 * i], self.data[2 * i + 1])

	def query(self, alpha, omega):
		if alpha == omega:
			return self.data[alpha + self.size]
		res = self.default
		alpha += self.size
		omega += self.size + 1
		while alpha < omega:
			if alpha & 1:
				res = self.func(res, self.data[alpha])
				alpha += 1
			if omega & 1:
				omega -= 1
				res = self.func(res, self.data[omega])
			alpha >>= 1
			omega >>= 1
		return res

	def update(self, index, value):
		index += self.size
		self.data[index] = value
		index >>= 1
		while index:
			self.data[index] = self.func(self.data[2 * index], self.data[2 * index + 1])
			index >>= 1
string1 = [2 ** (ord(k) - 97) for k in input()]
segtree = SegmentTree(string1)
for j in range(int(input())):
	val = list(input().split())
	if val[0] == '1':
		ind = int(val[1]) - 1
		v0 = ord(val[2]) - 97
		segtree.update(ind, 2 ** v0)
	else:
		ind1 = int(val[1]) - 1
		ind2 = int(val[2]) - 1
		ans = bin(segtree.query(ind1, ind2)).count('1')
		print(ans)


import sys
input = lambda : sys.stdin.readline().rstrip('\r\n')

def queries(l, r):
	global p
	l = p + l
	r = p + r
	count = 0
	n_seg_tree = [0 for i in range(26)]
	while l <= r:
		if l == r:
			break
		if l >> 1 != l + 1 >> 1:
			for i in range(26):
				n_seg_tree[i] += seg_tree[l][i]
			l += 1
		if l == r:
			break
		if r >> 1 != r - 1 >> 1 and l <= r:
			for i in range(26):
				n_seg_tree[i] += seg_tree[r][i]
			r -= 1
		l = l >> 1
		r = r >> 1
	for i in range(26):
		n_seg_tree[i] += seg_tree[l][i]
	for i in range(26):
		if n_seg_tree[i] > 0:
			count += 1
	return count

def update(pre, r, indx):
	while indx >= 1:
		seg_tree[indx][pre] -= 1
		seg_tree[indx][r] += 1
		indx = indx >> 1
ss = input()
st = []
for i in ss:
	st.append(i)
l = len(ss)
n = 1
while n <= l:
	n = n << 1
p = n - 1
n = n << 1
seg_tree = [[0 for i in range(26)] for j in range(n)]
for i in range(p + 1, p + l + 1):
	seg_tree[i][ord(st[i - p - 1]) - 97] = 1
q = p
while q >= 1:
	for i in range(26):
		seg_tree[q][i] = seg_tree[q << 1][i] + seg_tree[(q << 1) + 1][i]
	q -= 1
q = int(input())
for i in range(q):
	(a, b, c) = map(str, input().split())
	if int(a) == 1:
		update(ord(st[int(b) - 1]) - 97, ord(c) - 97, p + int(b))
		st[int(b) - 1] = c
	else:
		print(queries(int(b), int(c)))


import os
import sys
import math
from io import BytesIO, IOBase
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')

def update(v, w, s):
	while v <= length:
		l[s][v] += w
		v += v & -v

def get_value(v, s):
	ans = 0
	while v != 0:
		ans += l[s][v]
		v -= v & -v
	return ans
from sys import stdin, stdout
s = list(stdin.readline().strip())
q = int(stdin.readline())
length = len(s)
l = [[0 for i in range(length + 1)] for _ in range(26)]
for i in range(length):
	x = ord(s[i]) - 97
	update(i + 1, 1, x)
for _ in range(q):
	(n, m, k) = stdin.readline().split()
	if n == '1':
		a = s[int(m) - 1]
		(x, y) = (ord(a) - 97, ord(k) - 97)
		update(int(m), -1, x)
		update(int(m), 1, y)
		s[int(m) - 1] = k
	else:
		count = 0
		(left, r) = (int(m), int(k))
		for i in range(26):
			if get_value(r, i) - get_value(left - 1, i) >= 1:
				count += 1
		print(count)


import os, sys, math
import collections
if os.path.exists('testing'):
	name = os.path.basename(__file__)
	if name.endswith('.py'):
		name = name[:-3]
	src = open(name + '.in.txt', encoding='utf8')
	input = src.readline
tree_size_bits = int(math.floor(math.log2(10 ** 5))) + 1
letter_count = ord('z') - ord('a') + 1

def solve(s, commands):
	tree = [0] * 2 ** (tree_size_bits + 1)
	data = [None] * len(s)

	def set_char(pos, c):
		full_mask = (1 << letter_count) - 1
		remove_mask = 1 << data[pos] if data[pos] is not None else 0
		add_index = ord(c) - ord('a')
		add_mask = 1 << add_index
		if remove_mask == add_mask:
			return
		data[pos] = add_index
		pos = 2 ** tree_size_bits + pos
		tree[pos] = tree[pos] & (full_mask ^ remove_mask) | add_mask
		while pos > 1:
			parent = pos // 2
			child1 = parent * 2 + 0
			child2 = parent * 2 + 1
			new_value = tree[child1] | tree[child2]
			if tree[parent] == new_value:
				break
			tree[parent] = new_value
			pos = parent

	def query(pos1, pos2):

		def query_rec(array_index, lower_bound, upper_bound):
			if pos1 <= lower_bound and upper_bound <= pos2:
				return tree[array_index]
			if pos1 > upper_bound or pos2 < lower_bound:
				return 0
			split_value = (lower_bound + upper_bound + 1) // 2
			return query_rec(array_index * 2 + 0, lower_bound, split_value - 1) | query_rec(array_index * 2 + 1, split_value, upper_bound)
		return query_rec(1, 0, 2 ** tree_size_bits - 1)
	for (e, char) in enumerate(s):
		set_char(e, char)
	result = []
	for (c, a, b) in commands:
		if c == '1':
			pos = int(a) - 1
			char = b
			set_char(pos, char)
		else:
			lower_bound = int(a) - 1
			upper_bound = int(b) - 1
			characters = query(lower_bound, upper_bound)
			count = 0
			while characters:
				if characters & 1:
					count += 1
				characters = characters >> 1
			result.append(count)
	return result
s = input().strip()
num = int(input().strip())
commands = [input().strip().split() for _ in range(num)]
r = solve(s, commands)
for q in r:
	print(q)


import os
import sys
from io import BytesIO, IOBase

def main():
	arr = list(map(lambda x: 1 << ord(x) - ord('a'), input()))
	n = len(arr)
	h = (n - 1).bit_length()
	size = 2 * (1 << h) - 1
	segTree = [0] * size

	def construct(l, r, i):
		if l == r:
			segTree[i] = arr[l]
			return segTree[i]
		mid = l + (r - l) // 2
		segTree[i] = construct(l, mid, 2 * i + 1) | construct(mid + 1, r, 2 * i + 2)
		return segTree[i]
	construct(0, n - 1, 0)

	def queries(start, end, l, r, i):
		if end < l or start > r:
			return 0
		if l <= start and r >= end:
			return segTree[i]
		mid = start + (end - start) // 2
		return queries(start, mid, l, r, 2 * i + 1) | queries(mid + 1, end, l, r, 2 * i + 2)

	def update(i, val, start, end, pos):
		if i < start or i > end:
			return segTree[pos]
		if start == end:
			segTree[pos] = val
			arr[i] = val
			return segTree[pos]
		mid = start + (end - start) // 2
		segTree[pos] = update(i, val, start, mid, 2 * pos + 1) | update(i, val, mid + 1, end, 2 * pos + 2)
		return segTree[pos]
	q = int(input())
	for _ in range(q):
		(x, y, z) = input().split()
		if x == '1':
			y = int(y)
			update(y - 1, 1 << ord(z) - ord('a'), 0, n - 1, 0)
		else:
			y = int(y)
			z = int(z)
			print(bin(queries(0, n - 1, y - 1, z - 1, 0)).count('1'))
BUFSIZE = 8192

class FastIO(IOBase):
	newlines = 0

	def __init__(self, file):
		self._fd = file.fileno()
		self.buffer = BytesIO()
		self.writable = 'x' in file.mode or 'r' not in file.mode
		self.write = self.buffer.write if self.writable else None

	def read(self):
		while True:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			if not b:
				break
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines = 0
		return self.buffer.read()

	def readline(self):
		while self.newlines == 0:
			b = os.read(self._fd, max(os.fstat(self._fd).st_size, BUFSIZE))
			self.newlines = b.count(b'\n') + (not b)
			ptr = self.buffer.tell()
			(self.buffer.seek(0, 2), self.buffer.write(b), self.buffer.seek(ptr))
		self.newlines -= 1
		return self.buffer.readline()

	def flush(self):
		if self.writable:
			os.write(self._fd, self.buffer.getvalue())
			(self.buffer.truncate(0), self.buffer.seek(0))

class IOWrapper(IOBase):

	def __init__(self, file):
		self.buffer = FastIO(file)
		self.flush = self.buffer.flush
		self.writable = self.buffer.writable
		self.write = lambda s: self.buffer.write(s.encode('ascii'))
		self.read = lambda : self.buffer.read().decode('ascii')
		self.readline = lambda : self.buffer.readline().decode('ascii')
(sys.stdin, sys.stdout) = (IOWrapper(sys.stdin), IOWrapper(sys.stdout))
input = lambda : sys.stdin.readline().rstrip('\r\n')
main()


import array
import math
import os
import sys

def main():
	S = inp()
	Q = read_int()
	A = []
	for _ in range(Q):
		(a, b, c) = inp().split()
		ia = int(a)
		if ia == 1:
			A.append((1, int(b) - 1, c))
		else:
			A.append((2, int(b) - 1, int(c)))
	print(*solve(S, Q, A), sep='\n')

def ci(c):
	return ord(c) - ord('a')

def solve(S, Q, A):
	segt = [[1 << ci(c) for c in S]]
	while len(segt[-1]) > 1:
		lseg = segt[-1]
		if len(lseg) % 2 == 1:
			lseg.append(0)
		seg = []
		for i in range(len(lseg) // 2):
			seg.append(lseg[2 * i] | lseg[2 * i + 1])
		segt.append(seg)
	ans = []
	for (a, b, c) in A:
		if a == 1:
			segt[0][b] = 1 << ci(c)
			i = b // 2
			j = 1
			while j < len(segt):
				lseg = segt[j - 1]
				seg = segt[j]
				seg[i] = lseg[2 * i] | lseg[2 * i + 1]
				i //= 2
				j += 1
		else:
			res = 0
			j = 0
			while c - b >= 1:
				if b % 2 == 1:
					res |= segt[j][b]
					b += 1
				if c % 2 == 1:
					res |= segt[j][c - 1]
					c -= 1
				b //= 2
				c //= 2
				j += 1
			ans.append('{:b}'.format(res).count('1'))
	return ans
DEBUG = 'DEBUG' in os.environ

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

def read_int():
	return int(inp())

def read_ints():
	return [int(e) for e in inp().split()]

def dprint(*value, sep=' ', end='\n'):
	if DEBUG:
		print(*value, sep=sep, end=end)
main()


from collections import defaultdict as dc
from collections import deque as dq
from bisect import bisect_left, bisect_right, insort_left
import sys
import math
mod = 10 ** 9 + 7

def bs(a, x):
	i = bisect_left(a, x)
	if i != len(a) and a[i] == x:
		return i
	else:
		return -1

def inp():
	p = sys.stdin.readline()
	return p

def line():
	p = sys.stdin.readline().split()
	return p
s = str(input())
n = len(s)
p = [[0] * (n + 1) for i in range(26)]

def update(p, i, x, n, val):
	x += 1
	while x <= n:
		p[i][x] += val
		x += -x & x

def getsum(p, i, x):
	ans = 0
	while x > 0:
		ans = ans + p[i][x]
		x -= -x & x
	return ans
for i in range(n):
	update(p, ord(s[i]) - 97, i, n, 1)
q = int(inp())
s = list(s)
for i in range(q):
	(t, l, r) = line()
	l = int(l) - 1
	if int(t) == 1:
		z = s[l]
		update(p, ord(z) - 97, l, n, -1)
		s[l] = r
		update(p, ord(r) - 97, l, n, 1)
	else:
		c = 0
		l = l + 1
		r = int(r)
		for h in range(26):
			if getsum(p, h, r) - getsum(p, h, l - 1) > 0:
				c += 1
		print(c)


import sys
input = sys.stdin.readline
import collections

class SegmentTree:

	class Node:

		def __init__(self, l, r, m):
			self.left = None
			self.right = None
			self.range = [l, r]
			self.m = m

	def __init__(self, s):
		self.s = list(s)
		self.root = self.create_node(s, 0, len(s) - 1)

	def create_node(self, s, l, r):
		m = [0] * 26
		for i in range(l, r + 1):
			m[ord(s[i]) - ord('a')] += 1
		root = self.Node(l, r, m)
		if l != r:
			root.left = self.create_node(s, l, (l + r) // 2)
			root.right = self.create_node(s, (l + r) // 2 + 1, r)
		return root

	def update(self, pos, c):
		p = self.root
		prec = self.s[pos]
		while p:
			p.m[ord(prec) - ord('a')] -= 1
			p.m[ord(c) - ord('a')] += 1
			if pos <= (p.range[0] + p.range[1]) // 2:
				p = p.left
			else:
				p = p.right
		self.s[pos] = c

	def get(self, l, r):
		m = self.dfs(self.root, l, r)
		return sum((v != 0 for v in m))

	def dfs(self, p, l, r):

		def combine(m1, m2):
			for i in range(26):
				m1[i] += m2[i]
		if not p:
			return {}
		if r < p.range[0] or p.range[1] < l:
			return [0] * 26
		if l <= p.range[0] and p.range[1] <= r:
			return p.m
		m = [0] * 26
		if l <= (p.range[0] + p.range[1]) // 2:
			combine(m, self.dfs(p.left, l, r))
		if r > (p.range[0] + p.range[1]) // 2:
			combine(m, self.dfs(p.right, l, r))
		return m

def main():
	s = input().strip()
	st = SegmentTree(s)
	nq = int(input())
	for _ in range(nq):
		(tp, b, c) = input().split()
		if tp == '1':
			st.update(int(b) - 1, c)
		else:
			print(st.get(int(b) - 1, int(c) - 1))
main()


def solve(s, qs):
	n = len(s)
	bits = [[0 for i in range(n + 1)] for j in range(26)]

	def update(i, j, val):
		while j <= n:
			bits[i][j] += val
			j += j & -j

	def _query(i, j):
		s = 0
		while j > 0:
			s += bits[i][j]
			j -= j & -j
		return s

	def query(i, a, b):
		return _query(i, b) - _query(i, a - 1)
	for (i, c) in enumerate(s):
		update(c - ord('a'), i + 1, 1)
	for q in qs:
		if q[0] == 1:
			update(s[q[1] - 1] - ord('a'), q[1], -1)
			s[q[1] - 1] = q[2]
			update(q[2] - ord('a'), q[1], 1)
		else:
			ans = 0
			for i in range(26):
				ans += query(i, q[1], q[2]) > 0
			print(ans)
s = [ord(c) for c in input()]
qs = [input().split() for i in range(int(input()))]
for i in range(len(qs)):
	q = qs[i]
	if q[0] == '1':
		qs[i] = [int(q[0]), int(q[1]), ord(q[2])]
	else:
		qs[i] = list(map(int, q))
solve(s, qs)


from math import log
N = pow(2, 17) + 100
tree = [0] * (2 * N)

def build(arr):
	for i in range(n):
		bits = list('0' * 26)
		bits[25 - ord(arr[i]) + 97] = '1'
		tree[n + i] = int(''.join(bits), 2)
	for i in range(n - 1, 0, -1):
		tree[i] = tree[i << 1] | tree[i << 1 | 1]

def updateTreeNode(p, value):
	bits = list('0' * 26)
	bits[25 - ord(value) + 97] = '1'
	tree[p + n] = int(''.join(bits), 2)
	p = p + n
	i = p
	while i > 1:
		tree[i >> 1] = tree[i] | tree[i ^ 1]
		i >>= 1

def query(l, r):
	res = 0
	l += n
	r += n
	while l < r:
		if l & 1:
			res |= tree[l]
			l += 1
		if r & 1:
			r -= 1
			res |= tree[r]
		l >>= 1
		r >>= 1
	res = sum([int(x) for x in bin(res)[2:]])
	return res
a = list(input())
n = len(a)
quries = int(input())
b = build(a)
for _ in range(quries):
	(q, a, b) = list(input().split())
	if q == '2':
		print(query(int(a) - 1, int(b)))
	else:
		updateTreeNode(int(a) - 1, b)


import math, sys, bisect, heapq, os
from collections import defaultdict, Counter, deque
from itertools import groupby, accumulate
from functools import lru_cache
int1 = lambda x: int(x) - 1

def input():
	return sys.stdin.readline().rstrip('\r\n')
aj = lambda : list(map(int, input().split()))

def list3d(a, b, c, d):
	return [[[d] * c for j in range(b)] for i in range(a)]

def Y(c):
	print(['NO', 'YES'][c])

def y(c):
	print(['no', 'yes'][c])

def Yy(c):
	print(['No', 'Yes'][c])

def solve():
	D = {}
	for i in range(26):
		D[i] = 1 << i

	def Set(a):
		num = ord(a) - ord('a')
		return D[num]

	def Count(n):
		return bin(n).count('1')

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

	def update(seg, n, a, b):
		a += n
		seg[a] = Set(b)
		while a > 1:
			a >>= 1
			seg[a] = merge(seg[2 * a], seg[2 * a + 1])

	def query(seg, n, ntrl, l, r):
		r += 1
		l += n
		r += n
		tot = ntrl
		while l < r:
			if l & 1:
				tot = merge(tot, seg[l])
				l += 1
			if r & 1:
				r -= 1
				tot = merge(tot, seg[r])
			l = l // 2
			r = r // 2
		return Count(tot)

	def construct(A, ntrl):
		n = len(A)
		seg = [ntrl] * (2 * n)
		for i in range(n):
			seg[n + i] = Set(A[i])
		for i in range(n - 1, 0, -1):
			seg[i] = merge(seg[2 * i], seg[2 * i + 1])
		return seg
	A = [*input()]
	ntrl = 0
	n = len(A)
	seg = construct(A, ntrl)
	for _ in range(int(input())):
		(a, b, c) = input().split(' ')
		if a == '1':
			update(seg, n, int(b) - 1, c)
		else:
			print(query(seg, n, ntrl, int(b) - 1, int(c) - 1))
try:
	sys.stdin = open('input.txt', 'r')
	sys.stdout = open('output.txt', 'w')
except:
	pass
solve()


class SegmentTree(object):

	def __init__(self, init_val: 'Initial Array (List)', segfunc: 'Operation when update', ide_ele: 'Identity element corresponding init_val'=0):
		self.segfunc = segfunc
		self.size = 1 << len(bin(len(init_val) - 1)) - 2
		self.ide_ele = ide_ele
		self.tree = self._build(init_val)

	def _build(self, init_val):
		tree = [self.ide_ele] * self.size + init_val + [self.ide_ele] * (self.size - len(init_val))
		for idx in range(self.size - 1, 0, -1):
			tree[idx] = self.segfunc(tree[2 * idx + 1], tree[2 * idx])
		return tree

	def update(self, idx, val):
		idx += self.size
		self.tree[idx] = val
		while idx > 1:
			idx >>= 1
			self.tree[idx] = self.segfunc(self.tree[idx * 2 + 1], self.tree[idx * 2])

	def query(self, left: int, right: int):
		left += self.size
		right += self.size
		ret = self.segfunc(self.tree[left], self.tree[right])
		while left < right - 1:
			if not left & 1:
				ret = self.segfunc(ret, self.tree[left + 1])
			if right & 1:
				ret = self.segfunc(ret, self.tree[right - 1])
			left >>= 1
			right >>= 1
		return ret
import sys
input = sys.stdin.readline

def solver():
	s = input()[:-1]
	n = int(input()[:-1])
	segfunc = lambda x, y: x | y
	vals = [1 << ord(i) - 97 for i in s]
	seg = SegmentTree(vals, segfunc)
	for i in range(n):
		(a, b, c) = input()[:-1].split()
		if a == '1':
			val = 1 << ord(c) - 97
			seg.update(int(b) - 1, val)
		else:
			(left, right) = (int(b) - 1, int(c) - 1)
			ret = seg.query(left, right)
			ans = bin(ret).count('1')
			print(ans)

def main():
	while True:
		try:
			solver()
		except EOFError:
			break
solver()


import sys
input = lambda : sys.stdin.readline().rstrip('\r\n')

class segtree:

	def __init__(self, a):
		self.size = 1
		while self.size < len(a):
			self.size *= 2
		self.tree = [0] * (2 * self.size)
		self.build(a, 0, 0, self.size)

	def build(self, a, x, lx, rx):
		if rx - lx == 1:
			if lx < len(a):
				self.tree[x] = 1 << ord(a[lx]) - ord('a')
			return
		m = lx + rx >> 1
		self.build(a, 2 * x + 1, lx, m)
		self.build(a, 2 * x + 2, m, rx)
		self.tree[x] = self.tree[2 * x + 1] | self.tree[2 * x + 2]

	def update(self, i, v, x, lx, rx):
		if rx - lx == 1:
			self.tree[x] = 1 << ord(v) - ord('a')
			return
		m = lx + rx >> 1
		if i < m:
			self.update(i, v, 2 * x + 1, lx, m)
		else:
			self.update(i, v, 2 * x + 2, m, rx)
		self.tree[x] = self.tree[2 * x + 1] | self.tree[2 * x + 2]

	def set(self, i, v):
		self.update(i, v, 0, 0, self.size)

	def query1(self, l, r, x, lx, rx):
		if rx <= l or lx >= r:
			return 0
		if lx >= l and rx <= r:
			return self.tree[x]
		m = lx + rx >> 1
		return self.query1(l, r, 2 * x + 1, lx, m) | self.query1(l, r, 2 * x + 2, m, rx)

	def query(self, l, r):
		x = self.query1(l, r, 0, 0, self.size)
		return bin(x).count('1')
s = list(input())
q = int(input())
st = segtree(s)
for _ in range(q):
	ip = input().split()
	if ip[0] == '1':
		(i, v) = (int(ip[1]), ip[2])
		i -= 1
		st.set(i, v)
	else:
		(l, r) = (int(ip[1]), int(ip[2]))
		print(st.query(l - 1, r))


from sys import stdin
inp = stdin.readline

class SegmentTree:

	def __init__(self, values, default, func):
		k = 0
		while 2 ** k < len(values):
			k += 1
		heap = (2 ** k - 1) * [default] + list(values) + (2 ** k - len(values)) * [default]
		for index in range(2 ** k - 1 - 1, -1, -1):
			heap[index] = func(heap[2 * index + 1], heap[2 * index + 2])
		self._length = len(values)
		self.func = func
		self.heap = heap
		self.k = k
		self.default = default

	def __getitem__(self, indexer):
		shift = 2 ** self.k - 1
		if isinstance(indexer, int):
			return self.heap[shift + indexer]
		elif isinstance(indexer, slice):
			(left, right) = (shift + indexer.start, shift + indexer.stop - 1)
			if left > right:
				return self.default
			func = self.func
			heap = self.heap
			res = func(heap[left], heap[right])
			while left < right:
				if ~(left & 1):
					res = func(res, heap[left])
					left += 1
				if right & 1:
					res = func(res, heap[right])
					right -= 1
				left = (left + 1) // 2 - 1
				right = (right + 1) // 2 - 1
				if left == right:
					res = func(res, heap[left])
			return res
		raise TypeError()

	def __setitem__(self, array_index, value):
		if array_index > len(self):
			raise IndexError
		index = 2 ** self.k - 1 + array_index
		heap = self.heap
		func = self.func
		heap[index] = value
		while index:
			index = (index + 1) // 2 - 1
			heap[index] = func(heap[2 * index + 1], heap[2 * index + 2])

	def __len__(self):
		return self._length

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

def get_ones_place(c):
	place = 0
	while c:
		place += c & 1
		c >>= 1
	return place
s = list(inp()[:-1])
q = int(inp())
segment_tree = SegmentTree([get_binary(c) for c in s], 0, lambda x, y: x | y)
while q:
	q -= 1
	(a, b, c) = inp().split()
	if a == '1':
		segment_tree[int(b) - 1] = get_binary(c)
	else:
		print(get_ones_place(segment_tree[int(b) - 1:int(c)]))


import sys, os, io
input = sys.stdin.readline

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

class SegmentTree:

	def __init__(self, data, default=0, func=myFun):
		self._default = default
		self._func = func
		self._len = len(data)
		self._size = _size = 1 << (self._len - 1).bit_length()
		self.data = [default] * (2 * _size)
		self.data[_size:_size + self._len] = data
		for i in reversed(range(_size)):
			self.data[i] = func(self.data[i + i], self.data[i + i + 1])

	def __delitem__(self, idx):
		self[idx] = self._default

	def __getitem__(self, idx):
		return self.data[idx + self._size]

	def __setitem__(self, idx, value):
		idx += self._size
		self.data[idx] = value
		idx >>= 1
		while idx:
			self.data[idx] = self._func(self.data[2 * idx], self.data[2 * idx + 1])
			idx >>= 1

	def __len__(self):
		return self._len

	def query(self, start, stop):
		start += self._size
		stop += self._size
		res_left = res_right = self._default
		while start < stop:
			if start & 1:
				res_left = self._func(res_left, self.data[start])
				start += 1
			if stop & 1:
				stop -= 1
				res_right = self._func(self.data[stop], res_right)
			start >>= 1
			stop >>= 1
		return self._func(res_left, res_right)

	def __repr__(self):
		return 'SegmentTree({0})'.format(self.data)
s = input().strip()
a = [1 << ord(i) - 97 for i in s]
st = SegmentTree(a)
for _ in range(int(input())):
	q = [i for i in input().split()]
	if q[0] == '1':
		st.__setitem__(int(q[1]) - 1, 1 << ord(q[2]) - 97)
	else:
		print(bin(st.query(int(q[1]) - 1, int(q[2]))).count('1'))


import sys
s = list(sys.stdin.readline().strip())
n = len(s)
BIT = [[0] * (n + 1) for i in range(26)]

def update(i, idx, val):
	idx += 1
	while idx <= n:
		BIT[i][idx] += val
		idx += -idx & idx

def read(i, idx):
	ret = 0
	while idx > 0:
		ret += BIT[i][idx]
		idx -= -idx & idx
	return ret
for i in range(n):
	update(ord(s[i]) - 97, i, 1)
q = int(sys.stdin.readline())
for _ in range(q):
	(t, a, b) = sys.stdin.readline().split()
	if t == '1':
		idx = int(a) - 1
		bit_idx = ord(s[idx]) - 97
		update(bit_idx, idx, -1)
		s[idx] = b
		bit_idx = ord(b) - 97
		update(bit_idx, idx, 1)
	else:
		ans = 0
		(l, r) = (int(a), int(b))
		for i in range(26):
			ans += 1 if read(i, r) - read(i, l - 1) > 0 else 0
		print(ans)


def build(s, seg, l, r, v):
	if l == r:
		seg[v] = 1 << ord(s[l]) - ord('a')
	else:
		m = (l + r) // 2
		build(s, seg, l, m, 2 * v)
		build(s, seg, m + 1, r, 2 * v + 1)
		seg[v] = seg[2 * v] | seg[2 * v + 1]

def query(seg, ql, qr, l, r, v):
	if ql > qr:
		return 0
	elif ql == l and qr == r:
		return seg[v]
	else:
		m = (l + r) // 2
		return query(seg, ql, min(m, qr), l, m, 2 * v) | query(seg, max(ql, m + 1), qr, m + 1, r, 2 * v + 1)

def update(seg, pos, val, v, l, r):
	global s
	if l == r:
		seg[v] &= ~(1 << ord(s[pos]) - ord('a'))
		seg[v] = seg[v] | 1 << ord(val) - ord('a')
	else:
		m = (l + r) // 2
		if pos <= m:
			update(seg, pos, val, 2 * v, l, m)
		else:
			update(seg, pos, val, 2 * v + 1, m + 1, r)
		seg[v] = seg[2 * v + 1] | seg[2 * v]
s = list(input())
seg = [0 for i in range(4 * len(s) + 1)]
build(s, seg, 0, len(s) - 1, 1)
n = int(input())
for _ in range(n):
	a = [x for x in input().split()]
	if a[0] == '2':
		print(bin(query(seg, int(a[1]) - 1, int(a[2]) - 1, 0, len(s) - 1, 1)).count('1'))
	else:
		update(seg, int(a[1]) - 1, a[2], 1, 0, len(s) - 1)
		s[int(a[1]) - 1] = a[2]


import sys

def rint():
	return map(int, sys.stdin.readline().split())

def input():
	return sys.stdin.readline().rstrip('\n')

def lsbz(n):
	return n + 1 & ~n

class Bit:

	def __init__(self, l, value=0):
		self.tree_size = l
		self.tree = [value] * self.tree_size

	def csum(self, i):
		ans = 0
		while i >= 0:
			ans += self.tree[i]
			i -= lsbz(i)
		return ans

	def update(self, i, diff):
		while i < len(self.tree):
			self.tree[i] += diff
			i += lsbz(i)

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

def replace(cmd):
	pos = int(cmd[1]) - 1
	c = a2i(cmd[2])
	old_c = s[pos]
	if old_c == c:
		return
	b[old_c].update(pos, -1)
	b[c].update(pos, 1)
	s[pos] = c

def calc(cmd):
	l = int(cmd[1]) - 1
	r = int(cmd[2]) - 1
	ans = 0
	for i in range(a_len):
		if b[i].csum(r) - b[i].csum(l - 1):
			ans += 1
	return ans
a_len = ord('z') - ord('a') + 1
s = [a2i(a) for a in input()]
b = [Bit(len(s)) for i in range(a_len)]
for i in range(len(s)):
	b[s[i]].update(i, 1)
q = int(input())
for _ in range(q):
	cmd = input().split()
	if cmd[0] == '1':
		replace(cmd)
	if cmd[0] == '2':
		print(calc(cmd))


import sys
input = sys.stdin.readline

def make_tree(n):
	tree = [[0] * (n + 1) for _ in range(26)]
	return tree

def get_sum(i, j):
	s = 0
	while i > 0:
		s += tree[j][i]
		i -= i & -i
	return s

def add(i, j, x):
	while i <= n:
		tree[j][i] += x
		i += i & -i
s = ['?'] + list(input().rstrip())
n = len(s)
tree = make_tree(n)
for i in range(1, n):
	add(i, ord(s[i]) - 97, 1)
q = int(input())
for _ in range(q):
	t = list(input().rstrip().split())
	if t[0] == '1':
		(p, c) = (int(t[1]), t[2])
		add(p, ord(s[p]) - 97, -1)
		add(p, ord(c) - 97, 1)
		s[p] = c
	else:
		(l, r) = (int(t[1]), int(t[2]))
		ans = 0
		for i in range(26):
			if get_sum(r, i) - get_sum(l - 1, i):
				ans += 1
		print(ans)


class SegmentTree:

	def __init__(self, arr):
		n = len(arr)
		self.arr = arr
		self.tree = ['*'] * (4 * n)
		self._build(1, 0, n - 1)

	def _build(self, ti, tl, tr):
		if tl == tr:
			t = [0] * 26
			t[ord(self.arr[tl]) - ord('a')] = 1
			self.tree[ti] = t
			return
		m = (tl + tr) // 2
		self._build(2 * ti, tl, m)
		self._build(2 * ti + 1, m + 1, tr)
		o = [0] * 26
		for i in range(26):
			o[i] += self.tree[2 * ti][i]
			o[i] += self.tree[2 * ti + 1][i]
		self.tree[ti] = o

	def query(self, l, r):
		return self._query(l, r, 0, len(self.arr) - 1, 1)

	def _query(self, l, r, tl, tr, ti):
		if l == tl and r == tr:
			s = self.tree[ti]
			return s
		if l > r:
			return [0] * 26
		m = (tl + tr) // 2
		le = self._query(l, min(m, r), tl, m, 2 * ti)
		re = self._query(max(m + 1, l), r, m + 1, tr, 2 * ti + 1)
		o = [0] * 26
		for i in range(26):
			o[i] += le[i]
			o[i] += re[i]
		return o

	def update(self, pos, newv):
		self._update(pos, newv, 0, len(self.arr) - 1, 1)
		self.arr[pos] = newv

	def _update(self, pos, newv, tl, tr, ti):
		if tl == tr:
			t = [0] * 26
			t[ord(newv) - ord('a')] = 1
			self.tree[ti] = t
			return
		m = (tl + tr) // 2
		if pos <= m:
			self._update(pos, newv, tl, m, 2 * ti)
		else:
			self._update(pos, newv, m + 1, tr, 2 * ti + 1)
		d = ord(self.arr[pos]) - ord('a')
		self.tree[ti][d] -= 1
		self.tree[ti][ord(newv) - ord('a')] += 1

def find(a, qs):
	chars = [x for x in a]
	tree = SegmentTree(chars)
	ans = []
	for q in qs:
		(typ, y, x) = q.split(' ')
		if int(typ) == 1:
			tree.update(int(y) - 1, x)
		else:
			ret = tree.query(int(y) - 1, int(x) - 1)
			print(sum([int(x > 0) for x in ret]))
import sys

def test():
	a = sys.stdin.readline().strip()
	n = sys.stdin.readline().strip()
	n = int(n)
	qs = []
	for i in range(n):
		qs.append(sys.stdin.readline().strip())
	find(a, qs)
test()


from sys import stdin
from collections import deque
import math

def build_segment_tree(tree, string, index, start, end):
	if start > end:
		return
	if start == end:
		tree[index][ord(string[start]) - ord('a')] += 1
	else:
		mid = (start + end) // 2
		build_segment_tree(tree, string, 2 * index, start, mid)
		build_segment_tree(tree, string, 2 * index + 1, mid + 1, end)
		for i in range(26):
			tree[index][i] = tree[2 * index][i] + tree[2 * index + 1][i]

def combine(first, second):
	aux = [0] * 26
	for i in range(26):
		aux[i] = first[i] + second[i]
	return aux

def query(tree, a, index, start, end, qs, qe):
	if qs > end or qe < start:
		return [0] * 26
	if qs <= start and end <= qe:
		return tree[index][:]
	else:
		mid = (start + end) // 2
		left = query(tree, a, 2 * index, start, mid, qs, qe)
		right = query(tree, a, 2 * index + 1, mid + 1, end, qs, qe)
		return combine(left, right)

def update_node(tree, string, index, start, end, n_index, c):
	if n_index < start or n_index > end:
		return
	if start == end:
		tree[index][ord(string[n_index]) - ord('a')] -= 1
		tree[index][ord(c) - ord('a')] += 1
		string[n_index] = c
		return
	else:
		mid = (start + end) // 2
		update_node(tree, string, 2 * index, start, mid, n_index, c)
		update_node(tree, string, 2 * index + 1, mid + 1, end, n_index, c)
		aux = combine(tree[2 * index], tree[2 * index + 1])
		for i in range(26):
			tree[index][i] = aux[i]
		return
string = list(stdin.readline().strip())
n = len(string)
tree = [[0 for x in range(26)] for y in range(4 * n + 1)]
index = 1
start = 0
end = n - 1
build_segment_tree(tree, string, index, start, end)
q = int(stdin.readline().strip())
for _ in range(q):
	(t, x, y) = list(stdin.readline().split())
	if t == '1':
		update_node(tree, string, index, start, end, int(x) - 1, y)
	else:
		result = query(tree, string, index, start, end, int(x) - 1, int(y) - 1)
		count = 0
		for i in result:
			if i > 0:
				count += 1
		print(count)


input = __import__('sys').stdin.buffer.readline
w = str(input().decode().strip())
w = ['_'] + list(w)
tree = [[0 for j in range(26)] for i in range(len(w))]
q = int(input())

def add(p, c, v):
	c = ord(c) - ord('a')
	while p < len(tree):
		tree[p][c] += v
		p += p & -p

def query(p):
	sol = [0 for i in range(26)]
	while p > 0:
		for c in range(26):
			sol[c] += tree[p][c]
		p -= p & -p
	return sol
for i in range(1, len(w)):
	add(i, w[i], 1)
output = []
for _ in range(q):
	(t, a, b) = input().split()
	if t.decode().strip() == '1':
		p = int(a)
		add(p, w[p], -1)
		w[p] = b
		add(p, w[p], +1)
	else:
		(a, b) = (int(a), int(b))
		hi = query(b)
		lo = query(a - 1)
		for c in range(26):
			hi[c] -= lo[c]
		output.append(str(26 - hi.count(0)))
print('\n'.join(output))