# https://atcoder.jp/contests/abc157/tasks/abc157_e
# セグメント木
# 各文字をビットに対応させる(セグ木を26本持っても良い)
import sys
read = sys.stdin.readline


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


class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木 (下書き)
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l<r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l-1])
                l+=1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r-1])
            l >>=1
            r >>=1
        return res


def segfunc(x, y):
    # 処理したい内容
    return x | y


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


def bit_to_sum(n):
    return sum([(n >> i) & 1 for i in range(n.bit_length())])


N = read_a_int()
S = read()[:-1]
S_bit = [moji_to_bit(s) for s in S]

# build segment tree
st = SegmentTree(S_bit, segfunc, 0)

Q = read_a_int()
for q in range(Q):
    com, a, b = read().split()
    if int(com) == 1:
        i, c = int(a) - 1, b
        st.update(i, moji_to_bit(c))
    else:
        l, r = int(a) - 1, int(b)
        print(bit_to_sum(st.query(l, r))) import sys sys read = sys.stdin.readline read sys.stdin.readline sys.stdin sys stdin readline def read_a_int():
    return int(read()) read_a_int return int(read()) int(read()) int read() read class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木 (下書き)
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l<r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l-1])
                l+=1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r-1])
            l >>=1
            r >>=1
        return res SegmentTree def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木 (下書き)
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

     __init__ '''
        セグ木 (下書き)
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        ''' self.ide = identity_element self.ide self ide identity_element self.func = segfunc self.func self func segfunc n = len(ls) n len(ls) len ls self.num = 2 ** (n - 1).bit_length() self.num self num 2 ** (n - 1).bit_length() 2 (n - 1).bit_length() n - 1).bit_length n - 1 n 1 bit_length self.tree = [self.ide] * (2 * self.num - 1) self.tree self tree [self.ide] * (2 * self.num - 1) [self.ide] self.ide self ide 2 * self.num - 1 2 * self.num 2 self.num self num 1 for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
         i l enumerate(ls) enumerate ls self.tree[i + self.num - 1] = l self.tree[i + self.num - 1] self.tree self tree i + self.num - 1 i + self.num i self.num self num 1 l for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

     i range(self.num - 2, -1, -1) range self.num - 2 self.num self num 2 -1 -1 self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2]) self.tree[i] self.tree self tree i segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2]) segfunc self.tree[2 * i + 1] self.tree self tree 2 * i + 1 2 * i 2 i 1 self.tree[2 * i + 2] self.tree self tree 2 * i + 2 2 * i 2 i 2 self self ls: list ls segfunc segfunc identity_element identity_element def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

     update '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        ''' i += self.num - 1 i self.num - 1 self.num self num 1 self.tree[i] = x self.tree[i] self.tree self tree i x while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

     i i = (i - 1) // 2 i (i - 1) // 2 i - 1 i 1 2 self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2]) self.tree[i] self.tree self tree i self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2]) self.func self func self.tree[i * 2 + 1] self.tree self tree i * 2 + 1 i * 2 i 2 1 self.tree[i * 2 + 2] self.tree self tree i * 2 + 2 i * 2 i 2 2 self self i i x x def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l<r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l-1])
                l+=1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r-1])
            l >>=1
            r >>=1
        return res query '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        ''' if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
         r <= l r l return ValueError('invalid index (l,rがありえないよ)') ValueError('invalid index (l,rがありえないよ)') ValueError 'invalid index (l,rがありえないよ)' l += self.num l self.num self num r += self.num r self.num self num res = self.ide res self.ide self ide while l<r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l-1])
                l+=1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r-1])
            l >>=1
            r >>=1
         l<r l r if l & 1:
                res = self.func(res, self.tree[l-1])
                l+=1
             l & 1 l 1 res = self.func(res, self.tree[l-1]) res self.func(res, self.tree[l-1]) self.func self func res self.tree[l-1] self.tree self tree l-1 l 1 l+=1 l 1 if r & 1:
                r -= 1
                res = self.func(res, self.tree[r-1])
             r & 1 r 1 r -= 1 r 1 res = self.func(res, self.tree[r-1]) res self.func(res, self.tree[r-1]) self.func self func res self.tree[r-1] self.tree self tree r-1 r 1 l >>=1 l 1 r >>=1 r 1 return res res self self l l r r def segfunc(x, y):
    # 処理したい内容
    return x | y segfunc return x | y x | y x y x x y y def moji_to_bit(a):
    return 1 << (ord(a) - ord('a')) moji_to_bit return 1 << (ord(a) - ord('a')) 1 << (ord(a) - ord('a')) 1 ord(a) - ord('a') ord(a) ord a ord('a') ord 'a' a a def bit_to_sum(n):
    return sum([(n >> i) & 1 for i in range(n.bit_length())]) bit_to_sum (n >> i) & 1 for i in range(n.bit_length()) for i in range(n.bit_length()) i range(n.bit_length()) range n.bit_length() n.bit_length n bit_length for i in range(n.bit_length()) (n >> i) & 1 n >> i n i 1 return sum([(n >> i) & 1 for i in range(n.bit_length())]) sum([(n >> i) & 1 for i in range(n.bit_length())]) sum [(n >> i) & 1 for i in range(n.bit_length())] n n N = read_a_int() N read_a_int() read_a_int S = read()[:-1] S read()[:-1] () read :-1 -1 moji_to_bit(s) for s in S for s in S s S for s in S moji_to_bit(s) moji_to_bit s S_bit = [moji_to_bit(s) for s in S] S_bit [moji_to_bit(s) for s in S] st = SegmentTree(S_bit, segfunc, 0) st SegmentTree(S_bit, segfunc, 0) SegmentTree S_bit segfunc 0 Q = read_a_int() Q read_a_int() read_a_int for q in range(Q):
    com, a, b = read().split()
    if int(com) == 1:
        i, c = int(a) - 1, b
        st.update(i, moji_to_bit(c))
    else:
        l, r = int(a) - 1, int(b)
        print(bit_to_sum(st.query(l, r))) q range(Q) range Q com, a, b = read().split() com read().split() ().split () read split a b if int(com) == 1:
        i, c = int(a) - 1, b
        st.update(i, moji_to_bit(c))
    else:
        l, r = int(a) - 1, int(b)
        print(bit_to_sum(st.query(l, r))) int(com) == 1 int(com) int com 1 i, c = int(a) - 1, b i int(a) - 1 int(a) int a 1 c b st.update(i, moji_to_bit(c)) st.update st update i moji_to_bit(c) moji_to_bit c l, r = int(a) - 1, int(b) l int(a) - 1 int(a) int a 1 r int(b) int b print(bit_to_sum(st.query(l, r))) print bit_to_sum(st.query(l, r)) bit_to_sum st.query(l, r) st.query st query l r Q = read_a_int() read_a_int() Q c = int(a) - 1, b b c read = sys.stdin.readline sys.stdin.readline read i, c = int(a) - 1, b int(a) - 1 i def read_a_int():
    return int(read()) def read_a_int():
    return int(read()) read_a_int st = SegmentTree(S_bit, segfunc, 0) SegmentTree(S_bit, segfunc, 0) st def segfunc(x, y):
    # 処理したい内容
    return x | y def segfunc(x, y):
    # 処理したい内容
    return x | y segfunc S = read()[:-1] read()[:-1] S com, a, b = read().split() read().split() com a, b = read().split() read().split() a def bit_to_sum(n):
    return sum([(n >> i) & 1 for i in range(n.bit_length())]) def bit_to_sum(n):
    return sum([(n >> i) & 1 for i in range(n.bit_length())]) bit_to_sum def moji_to_bit(a):
    return 1 << (ord(a) - ord('a')) def moji_to_bit(a):
    return 1 << (ord(a) - ord('a')) moji_to_bit b = read().split() read().split() b N = read_a_int() read_a_int() N l, r = int(a) - 1, int(b) int(a) - 1 l r = int(a) - 1, int(b) int(b) r class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木 (下書き)
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l<r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l-1])
                l+=1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r-1])
            l >>=1
            r >>=1
        return res class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木 (下書き)
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l<r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l-1])
                l+=1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r-1])
            l >>=1
            r >>=1
        return res SegmentTree S_bit = [moji_to_bit(s) for s in S] [moji_to_bit(s) for s in S] S_bit
# https://atcoder.jp/contests/abc157/tasks/abc157_e
# セグメント木
# 各文字をビットに対応させる(セグ木を26本持っても良い)
import sys
read = sys.stdin.readline


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


class SegmentTree:
    def __init__(self, ls: list, segfunc, identity_element):
        '''
        セグ木 (下書き)
        一次元のリストlsを受け取り初期化する。O(len(ls))
        区間のルールはsegfuncによって定義される
        identity elementは単位元。e.g., 最小値を求めたい→inf, 和→0, 積→1, gcd→0
        [単位元](https://ja.wikipedia.org/wiki/%E5%8D%98%E4%BD%8D%E5%85%83)
        '''
        self.ide = identity_element
        self.func = segfunc
        n = len(ls)
        self.num = 2 ** (n - 1).bit_length()  # n以上の最小の2のべき乗
        self.tree = [self.ide] * (2 * self.num - 1)  # −1はぴったりに作るためだけど気にしないでいい
        for i, l in enumerate(ls):  # 木の葉に代入
            self.tree[i + self.num - 1] = l
        for i in range(self.num - 2, -1, -1):  # 子を束ねて親を更新
            self.tree[i] = segfunc(self.tree[2 * i + 1], self.tree[2 * i + 2])

    def update(self, i, x):
        '''
        i番目の要素をxに変更する(木の中間ノードも更新する) O(logN)
        '''
        i += self.num - 1
        self.tree[i] = x
        while i:  # 木を更新
            i = (i - 1) // 2
            self.tree[i] = self.func(self.tree[i * 2 + 1],
                                     self.tree[i * 2 + 2])

    def query(self, l, r):
        '''
        区間[l,r)に対するクエリをO(logN)で処理する。例えばその区間の最小値、最大値、gcdなど
        '''
        if r <= l:
            return ValueError('invalid index (l,rがありえないよ)')
        l += self.num
        r += self.num
        res = self.ide
        while l<r:  # 右から寄りながら結果を結合していくイメージ
            if l & 1:
                res = self.func(res, self.tree[l-1])
                l+=1
            if r & 1:
                r -= 1
                res = self.func(res, self.tree[r-1])
            l >>=1
            r >>=1
        return res


def segfunc(x, y):
    # 処理したい内容
    return x | y


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


def bit_to_sum(n):
    return sum([(n >> i) & 1 for i in range(n.bit_length())])


N = read_a_int()
S = read()[:-1]
S_bit = [moji_to_bit(s) for s in S]

# build segment tree
st = SegmentTree(S_bit, segfunc, 0)

Q = read_a_int()
for q in range(Q):
    com, a, b = read().split()
    if int(com) == 1:
        i, c = int(a) - 1, b
        st.update(i, moji_to_bit(c))
    else:
        l, r = int(a) - 1, int(b)
        print(bit_to_sum(st.query(l, r)))
