You are given a string S of length N consisting of lowercase English letters.

Process Q queries of the following two types:

* Type 1: change the i_q-th character of S to c_q. (Do nothing if the i_q-th character is already c_q.)
* Type 2: answer the number of different characters occurring in the substring of S between the l_q-th and r_q-th characters (inclusive).

Constraints

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

Input

Input is given from Standard Input in the following format:


N
S
Q
Query_1
\vdots
Query_Q


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


1 i_q c_q



2 l_q r_q


Output

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

Example

Input

7
abcdbbd
6
2 3 6
1 5 z
2 1 1
1 4 a
1 7 d
2 1 7


Output

3
1
5
import java.util.*;
import java.util.function.BiFunction;
import java.io.*;


public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        PrintWriter out = new PrintWriter(System.out);
        int N = sc.nextInt();
        char[] S = sc.next().toCharArray();
        int q = sc.nextInt();
        StringBuilder result = new StringBuilder();
        SegmentTree<Long> t = new SegmentTree<>(N, (x, y)->x|y, 0L);
        for(int i=0;i<N;i++){
            t.update(i, (x, y)->y, 1L<<(S[i]-'a'));
        }
        for(int i=0;i<q;i++){
            if(sc.nextInt()==1){
                int iq = sc.nextInt();
                char cq = sc.next().charAt(0);
                t.update(iq-1, (x, y)->y, 1L<<(cq-'a'));
            }
            else{
                int l = sc.nextInt();
                int r = sc.nextInt();
                long bit = t.query(l-1, r);
                result.append(Long.bitCount(bit)+"\n");
            }
        }

        out.println(result);
        out.flush();
    }

}

@SuppressWarnings("unchecked")
class SegmentTree<T> {
    private BiFunction<T, T, T> f;
    private int n;
    private T d1;
    private T[] dat;
    private  SegmentTree(T[] dat, int n_, BiFunction<T, T, T> f, T d1){
        this.f = f;
        this.d1 = d1;
        init(n_);
        build(dat);
    }

    public SegmentTree(T[] dat, BiFunction<T, T, T> f, T d1){
        this(dat, dat.length, f, d1);
    }

    public SegmentTree(int n_, BiFunction<T, T, T> f, T d1){
        this((T[]) new Object[0], n_, f, d1);
    }

    private void init(int n_){
        n = 1;
        while(n<n_) this.n *= 2;
        this.dat = (T[]) new Object[2 * this.n - 1];
    }

    private void build(T[] v){
        for(int i=0;i<n;i++) dat[i+n-1] = i < v.length ? v[i]: d1;
        for(int i=n-2;i>=0;i--) dat[i] = f.apply(dat[i*2+1], dat[i*2+2]);
    }

    public <E> void update(int k,BiFunction<T,E,T> g, E a){
        k += n-1;
        dat[k] = g.apply(dat[k], a);
        while(k>0){
            k = (k-1)/2;
            dat[k] = f.apply(dat[k*2+1], dat[k*2+2]);
        }
    }

    private T query(int a, int b, int k,int l, int r){
        if(r<=a || b<=l) return d1;
        if(a<=l&&r<=b) return dat[k];
        T vl = query(a, b, k*2+1, l, (l+r)/2);
        T vr = query(a, b, k*2+2, (l+r)/2, r);
        return f.apply(vl, vr);
    }

    public T query(int a, int b){
        return query(a, b, 0, 0, n);
    }
}