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 JavaScript (Node.js 12.16.1) (judge verdict: Accepted)

class SegmentTree {
  #a; #op; #n; #e;
  constructor(a,op=Math.min,e=Infinity){
    let n = 1;
    while ( n <= a.length ) n <<= 1;
    this.#a = Array(--n).fill(e).concat(a);
    this.#n = n;
    const l = this.#a.length;
    for ( let i = n-1; i >= 0; i-- ) {
      const x = (l>i+i+1)?this.#a[i+i+1]:e;
      const y = (l>i+i+2)?this.#a[i+i+2]:e;
      this.#a[i] = op( x, y );
    }
    this.#op = op;
    this.#e = e;
  }
  update(i,v){
    const a = this.#a, l = a.length, e = this.#e;
    a[i += this.#n] = v;
    while( i > 0 ) {
      i = i-1 >> 1;
      const x = (l>i+i+1)?a[i+i+1]:e;
      const y = (l>i+i+2)?a[i+i+2]:e;
      a[i] = this.#op( x, y );
    }
  }
  get(l,r) {
    const a = this.#a, e = this.#e, op = this.#op;
    return function q(l,r,x,y,i){
      if ( l <= x && y <= r ) return a[i];
      if ( l >= y || x >= r || a.length <= i) return e;
      return op(
        q(l,r,x,x+y>>1,i+i+1),
        q(l,r,x+y>>1,y,i+i+2)
      );  
    }(l,r,0,this.#n+1,0);
  }
}
console.log((args=>{
  const tmp = args.trim().split`\n`;
  const S = tmp[1].split``.map(v=>1<<(v.charCodeAt()-97)), Q = tmp[2]|0;
  const Query = tmp.slice(3).map(r=>r.split` `);
  const st = new SegmentTree(S,(a,b)=>a|b,0);
  const o = [];
  for ( let i = 0; i < Q; i++ ) {
    const [t,x,y] = Query[i];
    if ( t === '1' ) {
      st.update(x-1,1<<(y.charCodeAt()-97));
    } else {
      const b = st.get(x-1,y|0);
      let c = 0;
      for ( let i = 0; i < 26; i++ ) if ( b&1<<i ) c++;
      o.push(c);
    }
  }
  return o.join`\n`;
})(require('fs').readFileSync('/dev/stdin', 'utf8')));