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)

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

template<typename T>
void out(T x) { cout << x << endl; exit(0); }
#define watch(x) cout << (#x) << " is " << (x) << endl

const int maxn = 1e6 + 5;

int n;
string s;
int q;

struct segment_tree {
  
  struct node {
    bitset<26> s;
    node() {}

    node(char x) {
      s.set(x-'a');
    }
  };
  
  node merge(node x, node y) {
    node res;
    res.s = x.s | y.s;
    return res;
  }
  ///////
  int n;
  vector<node> t;
  segment_tree() {}
  void init(int n) {
    this->n = n;
    t.resize(4*n+10);
  }
  void build(int v, int tl, int tr) {
    if (tl == tr) {
      t[v] = node(s[tl]);
    } else {
      int tm = (tl+tr)/2;
      build(2*v, tl, tm);
      build(2*v+1, tm+1, tr);
      t[v] = merge(t[2*v], t[2*v+1]);
    }
  }
  node get(int v, int tl, int tr, int l, int r) {
    if (l > tr || r < tl) {
      return node();
    } else if (l <= tl && tr <= r) {
      return t[v];
    } else {
      int tm = (tl + tr)/2;
      return merge(get(2*v, tl, tm, l, r), get(2*v+1, tm+1, tr, l, r));
    }
  }
  void update(int v, int tl, int tr, int idx) {
    if (tl == tr) {
      assert(tl == idx);
      t[v] = node(s[idx]);
    } else {
      int tm = (tl + tr)/2;
      if (idx <= tm) {
        update(2*v, tl, tm, idx);
      } else {
        update(2*v+1, tm+1, tr, idx);
      }
      t[v] = merge(t[2*v], t[2*v+1]);
    }
    
  }
};

segment_tree t;

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

  cin>>n;
  cin>>s;
  s = "*" + s;
  t.init(n+10);
  t.build(1,1,n);

  cin>>q;
  while (q--) {
    int z; cin>>z;
    if (z == 1) {
      int idx; char c; cin>>idx>>c;
      s[idx] = c;
      t.update(1,1,n,idx);
    } else {
      int l,r; cin>>l>>r;
      cout<<t.get(1,1,n,l,r).s.count()<<"\n";
    }
  }

  return 0;
}
// don't forget to read in the input :^)