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# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Linq;
using System.Collections.Generic;

namespace Contest
{
    class Program
    {
        static void Main(string[] args)
        {
            ABC157E();
        }

        static void ABC157A()
        {
            var N = ReadInt();
            Console.WriteLine((N + 1) / 2);
        }
        static void ABC157B()
        {
            var A1 = ReadIntN();
            var A2 = ReadIntN();
            var A3 = ReadIntN();
            var N = ReadInt();

            var A = new int[3, 3];
            for (int i = 0; i < 3; ++i)
            {
                A[0, i] = A1[i];
                A[1, i] = A2[i];
                A[2, i] = A3[i];
            }
            var B = new bool[3, 3];
            for (int i = 0; i < N; ++i)
            {
                var b = ReadInt();
                for (int j1 = 0; j1 < 3; ++j1)
                {
                    for (int j2 = 0; j2 < 3; ++j2)
                    {
                        if (A[j1, j2] == b) { B[j1, j2] = true; }
                    }
                }
            }
            bool bingo = false;
            for (int i = 0; i < 3; ++i)
            {
                if (B[0, i] && B[1, i] && B[2, i]) { bingo = true; }
                if (B[i, 0] && B[i, 1] && B[i, 2]) { bingo = true; }
            }
            if (B[0, 0] && B[1, 1] && B[2, 2]) { bingo = true; }
            if (B[2, 0] && B[1, 1] && B[0, 2]) { bingo = true; }
            Console.WriteLine(bingo ? "Yes" : "No");
        }
        static void ABC157C()
        {
            var nm = ReadIntN();
            var N = nm[0];
            var M = nm[1];
            var sc = ReadTupleLong(M);

            var has = new bool[4];
            var cand = new long[4];
            bool ok = true;
            foreach (var t in sc)
            {
                var S = t.Item1;
                var C = t.Item2;
                if (has[S])
                {
                    if (cand[S] != C) { ok = false; }
                }
                else
                {
                    has[S] = true;
                    cand[S] = C;
                }
            }
            if (!ok) { Console.WriteLine("-1");return; }
            if (N == 1)
            {
                if (has[1])
                {
                    Console.WriteLine(cand[1]);return;
                }
                else
                {
                    Console.WriteLine(0); return;
                }
            }
            if (has[1] && cand[1] == 0) { Console.WriteLine("-1"); return; }
            if (!has[1]) { cand[1] = 1; }
            if (N == 2)
            {
                Console.WriteLine(cand[1]*10+cand[2]);return;
            }
            Console.WriteLine(cand[1] * 100 + cand[2] * 10 + cand[3]);
        }
        static void ABC157D()
        {
            var nmk = ReadIntN();
            var N = nmk[0];
            var M = nmk[1];
            var K = nmk[2];
            var ab = ReadTupleLong(M);
            var cd = ReadTupleLong(K);

            Dictionary<int, HashSet<int>> friend = new Dictionary<int, HashSet<int>>();
            Dictionary<int, HashSet<int>> block = new Dictionary<int, HashSet<int>>();
            for (int i = 1; i <= N; ++i)
            {
                friend.Add(i, new HashSet<int>());
                block.Add(i, new HashSet<int>());
            }
            foreach (var t in ab)
            {
                friend[(int)t.Item1].Add((int)t.Item2);
                friend[(int)t.Item2].Add((int)t.Item1);
            }
            foreach (var t in cd)
            {
                block[(int)t.Item1].Add((int)t.Item2);
                block[(int)t.Item2].Add((int)t.Item1);
            }

            var check = new bool[N + 1];
            var cand = new int[N + 1];
            for(int i = 1; i <= N; ++i)
            {
                if (check[i]) { continue; }
                HashSet<int> bfs = new HashSet<int>();
                bfs.Add(i);
                List<int> target = new List<int>();
                target.Add(i);
                while (target.Count > 0)
                {
                    List<int> next = new List<int>();
                    foreach (var p in target)
                    {
                        foreach (var f in friend[p])
                        {
                            if (!check[f])
                            {
                                check[f] = true;
                                next.Add(f);
                                bfs.Add(f);
                            }
                        }
                    }
                    target = next;
                }
                foreach(var person in bfs)
                {
                    cand[person] = bfs.Count - 1;
                    foreach (var fr in friend[person])
                    {
                        if (bfs.Contains(fr))
                        {
                            cand[person] -= 1;
                        }
                    }
                    foreach (var bl in block[person])
                    {
                        if (bfs.Contains(bl))
                        {
                            cand[person] -= 1;
                        }
                    }
                }
            }
            Console.WriteLine(String.Join(" ", Enumerable.Range(1, N).Select(i => cand[i])));
        }
        static void ABC157E()
        {
            var N = ReadInt();
            var S = ReadStr();
            var Q = ReadInt();

            var counter = new int[4][][];
            counter[0] = new int[5002][];
            counter[1] = new int[502][];
            counter[2] = new int[52][];
            counter[3] = new int[7][];
            for (int i = 0; i < counter.Length; ++i)
            {
                for(int j = 0; j < counter[i].Length; ++j)
                {
                    counter[i][j] = new int[26];
                }
            }
            var array = new int[N];
            for (int i = 0; i < N; ++i)
            {
                var c = S[i] - 'a';
                array[i] = c;
                counter[0][i / 100][c]++;
                counter[1][i / 1000][c]++;
                counter[2][i / 10000][c]++;
                counter[3][i / 100000][c]++;
            }

            for (int q = 0; q < Q; ++q)
            {
                var query = ReadStrN();
                if (query[0] == "1")
                {
                    var i = Convert.ToInt32(query[1]) - 1;
                    var c = Convert.ToChar(query[2]) - 'a';
                    var prev = array[i];
                    array[i] = c;
                    counter[0][i / 100][prev]--;
                    counter[1][i / 1000][prev]--;
                    counter[2][i / 10000][prev]--;
                    counter[3][i / 100000][prev]--;
                    counter[0][i / 100][c]++;
                    counter[1][i / 1000][c]++;
                    counter[2][i / 10000][c]++;
                    counter[3][i / 100000][c]++;
                }
                else
                {
                    var l = Convert.ToInt32(query[1]) - 1;
                    var r = Convert.ToInt32(query[2]) - 1;
                    var count = new int[26];
                    count[array[r]]++;
                    while (l < r)
                    {
                        if (r - l >= 100000 && l % 100000 == 0)
                        {
                            var c = counter[3][l / 100000];
                            for(int i = 0; i < 26; ++i)
                            {
                                count[i] += c[i];
                            }
                            l += 100000;
                            continue;
                        }
                        if (r - l >= 10000 && l % 10000 == 0)
                        {
                            var c = counter[2][l / 10000];
                            for (int i = 0; i < 26; ++i)
                            {
                                count[i] += c[i];
                            }
                            l += 10000;
                            continue;
                        }
                        if (r - l >= 1000 && l % 1000 == 0)
                        {
                            var c = counter[1][l / 1000];
                            for (int i = 0; i < 26; ++i)
                            {
                                count[i] += c[i];
                            }
                            l += 1000;
                            continue;
                        }
                        if (r - l >= 100 && l % 100 == 0)
                        {
                            var c = counter[0][l / 100];
                            for (int i = 0; i < 26; ++i)
                            {
                                count[i] += c[i];
                            }
                            l += 100;
                            continue;
                        }
                        count[array[l]]++;
                        l += 1;
                    }
                    int sum = 0;
                    for(int i = 0; i < 26; ++i)
                    {
                        if (count[i] > 0) { sum += 1; }
                    }
                    Console.WriteLine(sum);
                }
            }
        }
        static void ABC157F()
        {

        }

        class Util
        {
            public static readonly long P = 1000000007;

            public static long Sum(long[] array)
            {
                return Sum(array, array.Length);
            }
            public static long Sum(long[] array, int n)
            {
                long total = 0;
                for(int i = 0; i < n; ++i)
                {
                    total += array[i];
                }
                return total;
            }
            public static long Count(long[] array, long x)
            {
                return Count(array, x, array.Length);
            }
            public static long Count(long[] array, long x, int n)
            {
                long total = 0;
                for (int i = 0; i < n; ++i)
                {
                    total += (array[i] == x ? 1 : 0);
                }
                return total;
            }
            public static long[] ASum(long[] array)
            {
                var res = new long[array.Length + 1];
                for (int i = 0; i < array.Length; ++i)
                {
                    res[i + 1] = res[i] + array[i];
                }
                return res;
            }

            public static long GCD(long a, long b)
            {
                while (b > 0)
                {
                    var c = a % b;
                    a = b;
                    b = c;
                }
                return a;
            }
            public static bool IsPrime(long x)
            {
                var fact = Factorize(x);
                return fact.Count == 1 && fact.Values.ElementAt(0) == 1;
            }
            public static Dictionary<long,int> Factorize(long x)
            {
                var dict = new Dictionary<long, int>();
                long minp = 2;
                while (x > 1)
                {
                    bool ok = false;
                    for(long p = minp; p * p <= x; ++p)
                    {
                        if (x % p == 0)
                        {
                            if (!dict.ContainsKey(p))
                            {
                                dict.Add(p, 0);
                            }
                            dict[p]++;
                            minp = p;
                            x /= p;
                            ok = true;
                            break;
                        }
                    }
                    if (!ok)
                    {
                        if (!dict.ContainsKey(x)) { dict.Add(x, 0); }
                        dict[x]++;
                        break;
                    }
                }
                return dict;
            }
            public static long Inverse(long a, long p)
            {
                long b = p, c = 1, d = 0, e = 0, f = 0;
                while (b != 0)
                {
                    e = a / b;
                    f = b; b = a - e * b; a = f;
                    f = d; d = c - e * d; c = f;
                }
                c %= p;
                return c + (c < 0 ? p : 0);
            }
            public static long[] Facts(int n, long p)
            {
                var facts = new long[n + 1];
                facts[0] = 1;
                for (int i = 1; i <= n; ++i)
                {
                    facts[i] = (i * facts[i - 1]) % p;
                }
                return facts;
            }
            public static Func<int,int,long> Combin(int n, long P)
            {
                var fact = Facts(n, P);
                var inv = fact.Select(x => Inverse(x, P)).ToArray();
                return (N, M) =>
                {
                    if (N < 0 || N < M || M < 0) { return 0; }
                    return (((fact[N] * inv[M]) % P) * inv[N - M]) % P;
                };
            }

            /// <summary>
            /// Calc Combin(n,m) where n is large and m<=mMax
            /// </summary>
            public static Func<int,int,long> CombinLarge(int mMax, long p)
            {
                var inv = Enumerable.Range(0, mMax + 1).Select(x => Util.Inverse(x, Util.P)).ToArray();
                return (n, m) =>
                {
                    long mult = 1;
                    for (int i = 1; i <= m; ++i)
                    {
                        mult = (((mult * (n + 1 - i)) % Util.P) * inv[i]) % Util.P;
                    }
                    return mult;
                };
            }

            /// <summary>
            /// Calc 2^n mod p
            /// </summary>
            public static long Power2(long n, long p)
            {
                return Power(2, n, p);
            }
            public static long Power(long a, long n, long p)
            {
                long res = 1;
                long mult = a;
                for (int i = 0; i < 40; ++i)
                {
                    if ((n & ((long)1 << i)) > 0)
                    {
                        res = (res * mult) % p;
                    }
                    mult = (mult * mult) % p;
                }
                return res;
            }
        }

        static string ReadStr()
        {
            return Console.ReadLine();
        }
        static string[] ReadStrN()
        {
            return Console.ReadLine().Split(' ');
        }
        static int ReadInt()
        {
            return Convert.ToInt32(Console.ReadLine());
        }
        static int[] ReadIntN()
        {
            return Console.ReadLine().Split(' ').Select(s => Convert.ToInt32(s)).ToArray();
        }
        static long ReadLong()
        {
            return Convert.ToInt64(Console.ReadLine());
        }
        static long[] ReadLongN()
        {
            return Console.ReadLine().Split(' ').Select(s => Convert.ToInt64(s)).ToArray();
        }
        static Tuple<string, string>[] ReadTupleStr(int n)
        {
            List<Tuple<string, string>> list = new List<Tuple<string, string>>();
            for (int i = 0; i < n; ++i)
            {
                var ab = ReadStrN();
                list.Add(new Tuple<string, string>(ab[0], ab[1]));
            }
            return list.ToArray();
        }
        static Tuple<long, long>[] ReadTupleLong(int n)
        {
            List<Tuple<long, long>> list = new List<Tuple<long, long>>();
            for (int i = 0; i < n; ++i)
            {
                var ab = ReadLongN();
                list.Add(new Tuple<long, long>(ab[0], ab[1]));
            }
            return list.ToArray();
        }
        static Tuple<double, double>[] ReadTupleDouble(int n)
        {
            List<Tuple<double, double>> list = new List<Tuple<double, double>>();
            for (int i = 0; i < n; ++i)
            {
                var ab = ReadLongN();
                list.Add(new Tuple<double, double>(ab[0], ab[1]));
            }
            return list.ToArray();
        }
    }
}