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;
const int Maxn = 500005;
int Tree[26][4*Maxn];
int N,Q;
string S;
void UpData(char a,int Poi,int poi,int Left,int Right)
{
	if(Right<Poi||Left>Poi)	return;
	if(Left == Right&&Left == Poi) 
	{
		Tree[a-'a'][poi] = 1;
		return;	
	}
	int Mid = Left + (Right - Left)/2;
	Tree[a -'a'][poi] = 1;
	UpData(a,Poi,poi*2,Left,Mid);
	UpData(a,Poi,poi*2+1,Mid+1,Right);
}
void print_Tree(int poi,int left,int right)
{
	printf("%d %d %d\n",left,right,Tree['b'-'a'][poi]);
	if(left==right) return;
	int Mid = (left + right)/2;
	print_Tree(poi*2,left,Mid);
	print_Tree(poi*2+1,Mid+1,right);
	return;
}
void UpData1(int Poi,char Begin,int poi,int Left,int Right)
{
	if(Right<Poi||Left>Poi)	return ;
	if(Left == Right &&Left == Poi)
	{
		Tree[Begin - 'a'][poi]  = 0;
		return;
	}
	int Mid = Left +(Right - Left)/2;
	UpData1(Poi,Begin,poi*2,Left,Mid);
	UpData1(Poi,Begin,poi*2+1,Mid+1,Right);
	if(Tree[Begin - 'a'][poi*2]==Tree[Begin -'a'][poi*2+1]&&Tree[Begin - 'a'][poi*2]==0)
		Tree[Begin - 'a'][poi] = 0;
	else
		Tree[Begin - 'a'][poi] = 1;
	return;
}
bool Search(int poi,int Left,int Right,char a,int L,int R)
{
	if(Left > R||Right<L)	return false;
	if(Tree[a-'a'][poi]==0)	return false;
	if(L<=Left&&Right<=R&&Tree[a-'a'][poi]==1) return true;
	int Mid = Left + (Right -Left)/2;
	if(Search(poi*2,Left,Mid,a,L,R))
		return true;
	if(Search(poi*2+1,Mid+1,Right,a,L,R))
		return true;
	return false;
}
int main()
{
	
	cin>>N>>S>>Q;
	for(int i=0;i<S.length();i++)
	{
		UpData(S[i],i+1,1,1,N);	//字符串是从1开始的所以位置往后面移动一个 
	}
	while(Q--)
	{
		int zz;
		cin>>zz;
		if(zz==1)
		{
			int poi;
			char change;
			cin>>poi>>change;
			if(change == S[poi-1])
				continue;
			UpData(change,poi,1,1,N);
			UpData1(poi,S[poi-1],1,1,N);
			S[poi-1] = change;
		}
		else
		{
			int Left, Right;
			cin>>Left>>Right;
			int ans =0;
			for(int i=0;i<26;i++)
			{
				if(Search(1,1,N,'a'+i,Left,Right))
				{
					ans++;
				}
			}
			printf("%d\n",ans);
		}
	}
	return 0;
}