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 Java8 (OpenJDK 1.8.0) (judge verdict: Accepted)

import java.util.Scanner;

class Main{
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		int N=sc.nextInt();
		String S=sc.next();
		int Q=sc.nextInt();
		Segtree[] st=new Segtree[26];
		for(int i=0; i<26; i++) {
			st[i]=new Segtree(N+1);
			st[i].fill(0);
		}
		for(int i=0; i<N; i++) {		//1　はじまり
			int tmp=S.charAt(i)-'a';
			st[tmp].add(i+1, 1);
		}
		for(int i=0; i<Q; i++) {
			int q=sc.nextInt();
			if(q==1) {
				int iq = sc.nextInt();
				String cq =sc.next();
				int moto=0;
				 for(int k=0; k<26; k++) {
					 if(st[k].get(iq)>0) {
						 moto=k;
						 break;
					 }
				 }
				if(moto == cq.charAt(0) - 'a') {
					//
				}
				else {
					st[moto].add(iq, -1);
					st[cq.charAt(0) - 'a' ].add(iq, 1);
				}
			}
			else if(q==2) {
				int lq = sc.nextInt();
				int rq =sc.nextInt();
				int res = 0;
				for(int j=0; j<26; j++) {
					if(st[j].sum(lq, rq, 0, 0, (st[j].length()+1)/2) >0) {
						res++;
					}
				}
				pl(res);
			}
		}



	}
	public static void pl(Object o) {
		System.out.println(o);
	}
	static class Segtree{
		int[] Segtree;
		public Segtree(int vol){
			int truevol=calc_vol(vol);		//vol以上で最も小さい2ベキを求める
			Segtree=new int[truevol*2-1];
			for(int i=0; i<truevol*2-1; i++) {
				Segtree[i]=0;
			}
			//pl(truevol*2-1);
		}
		public void fill(int num) {		//特定の値にフィルする
			for(int i=0; i<Segtree.length; i++) {
				Segtree[i]=num;
			}
		}
		public int calc_vol(int vol) {	//2のべき乗の値のサイズにする
			int beki=0;
			int tmp=1;
			while(vol>=tmp) {
				tmp*=2;
				if(tmp==vol) {
					break;
				}
				beki++;
			}
			return tmp;
		}
		public int get(int elem) {		//値を返す
			int leaf=elem-1+(length()+1)/2;	//更新するセグ木の末端
			return Segtree[leaf];
		}
		public int getParent(int num) {	//親取得
			return (num-1)/2;
		}
		public int getChild(int num) {	//子取得
			return num*2+1;	//子は2つあるが、そのうち数が若いほう
		}
		public void add(int elem,int num) {	//elem番目の要素にnum足す(elemは0オリジン)
			int leaf=elem-1+(length()+1)/2;	//更新するセグ木の末端
			boolean zero=false;	//0までたどり着いたか
			while(!zero && leaf>=0) {
				//pl(leaf);
				Segtree[leaf]+=num;
				if(leaf==0) {
					zero=true;
				}
				leaf=getParent(leaf);	//上に（根の方）近づく
			}
		}
		public int sum(int a, int b, int k, int l, int r) {//sum(a, b, 0, 0, seg.tree.length/2)
			//[a,b]の要素の和を求める
			//pl(a+" "+b+" "+k+" "+l+" "+r);
			if(r <= a || b < l) return 0; //区間が交わっていないなら0
			if(a <= l && r-1 <= b) return Segtree[k]; //[l,r)が完全に[a,b)に内包されているならそのノードを返す
			else {
				int vl = sum(a, b, k*2+1, l, (l+r)/2);
				int vr = sum(a, b, k*2+2, (l+r)/2, r);
				return vl + vr;
			}
		}
		public int length() {
			return Segtree.length;
		}
	}

}