Problem:
Score : 500 points

Problem Statement

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

Process Q queries of the following two types:

Type 1: change the i_q-th character of S to c_q. (Do nothing if the i_q-th character is already c_q.)

Type 2: answer the number of different characters occurring in the substring of S between the l_q-th and r_q-th characters (inclusive).

Constraints

N, Q, i_q, l_q, and r_q are integers.

S is a string consisting of lowercase English letters.

c_q is a lowercase English letter.

1 \leq N \leq 500000

1 \leq Q \leq 20000

|S| = N

1 \leq i_q \leq N

1 \leq l_q \leq r_q \leq N

There is at least one query of type 2 in each testcase.

Input

Input is given from Standard Input in the following format:

N
S
Q
Query_1
\vdots
Query_Q

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

1 i_q c_q

2 l_q r_q

Output

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

Sample Input 1

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

Sample Output 1

3
1
5

In the first query, cdbb contains three kinds of letters: b , c , and d, so we print 3.

In the second query, S is modified to abcdzbd.

In the third query, a contains one kind of letter: a, so we print 1.

In the fourth query, S is modified to abcazbd.

In the fifth query, S does not change and is still abcazbd.

In the sixth query, abcazbd contains five kinds of letters: a, b, c, d, and z, so we print 5.

Solution in C++14 (GCC 5.4.1) (judge verdict: Accepted)

#pragma GCC optimize("O3")
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <string>
#include <cstring>
#include <deque>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <utility>
#include <algorithm>
#include <map>
#include <set>
#include <complex>
#include <cmath>
#include <limits>
#include <cfloat>
#include <climits>
#include <ctime>
#include <cassert>
#include <numeric>
#include <fstream>
#include <functional>
#include <bitset>
using namespace std;

using ll = long long;
using P = pair<int, int>;
using T = tuple<int, int, int>;

template <class T> inline T chmax(T &a, const T b) {return a = (a < b) ? b : a;}
template <class T> inline T chmin(T &a, const T b) {return a = (a > b) ? b : a;}

constexpr int MOD = 1e9 + 7;
constexpr int inf = 1e9;
constexpr long long INF = 1e18;
constexpr double pi = acos(-1);
constexpr double EPS = 1e-10;

int dx[] = {1, 0, -1, 0};
int dy[] = {0, 1, 0, -1};


template<typename T>
struct Segtree {
    int n;
    T e;
    vector<T> dat;
    typedef function<T(T a, T b)> Func;
    Func f;
 
    Segtree(int n_input, Func f, T e_input):f(f), e(e_input){
        n = 1;
        while(n < n_input) n <<= 1;
        dat.resize(2*n-1, e);
    }
 
    void update(int k, T a){
        k += n - 1;
        dat[k] = a;
        while(k > 0){
            k = (k - 1)/2;
            dat[k] = f(dat[2*k+1], dat[2*k+2]);
        }
    }
 
    T between(int a, int b){
        return query(a, b+1, 0, 0, n);
    }
 
    T query(int a, int b, int k, int l, int r){
        if(r<=a || b<=l) return e;
        if(a<=l && r<=b) return dat[k];
        T vl = query(a, b, 2*k+1, l, (l+r)/2);
        T vr = query(a, b, 2*k+2, (l+r)/2, r);
        return f(vl, vr);
    }
};

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n; cin>>n;
    string s; cin>>s;

    map<char, ll> s2num;
    ll num = 1;
    for(char ch='a'; ch<='z'; ch++){
        s2num[ch] = num;
        num *= 2;
    }

    vector<ll> tmp(n);
    for(int i=0; i<n; i++){
        char t = s[i];
        ll cur = s2num[t];
        tmp[i] = cur;
    }

    Segtree<int> stOR(n, [](ll a, ll b){ return a|b;}, 0);
    for(int i=0; i<n; i++) stOR.update(i, tmp[i]);

    /*
    for(int i=0; i<n; i++){
        cout << stOR.dat[i] << " ";
    }
    */

    int q; cin>>q;
    while(q--){
        int Q; cin>>Q;
        if(Q == 1){
            int i; cin>>i;
            char c; cin>>c;
            i--;
            int cur = tmp[i];
            stOR.update(i, -cur);
            int nxt = s2num[c];
            tmp[i] = nxt;
            stOR.update(i, nxt);
        }
        else{
            int l, r; cin>>l>>r;
            l--, r--;
            ll sum = stOR.between(l, r);
            int bcnt = __builtin_popcountll(sum);
            cout << bcnt << endl;
        }
    }

    return 0;
}