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 Rust (1.15.1) (judge verdict: Accepted)

// The main code is at the very bottom.

#[allow(unused_imports)]
#[macro_use]
pub mod spella {
  #[macro_use]
  mod internal {
    macro_rules! rev {
      ($m:ident [$($t_front:tt)*] [] [$($t_rear:tt)*]) => {
        $m! { $($t_front)* $($t_rear)* }
      };
      ($m:ident [$($t_front:tt)*] [$t_head:tt, $($t_tail:tt,)*] [$($t_rear:tt)*]) => {
        rev! { $m [$($t_front)*] [$($t_tail,)*] [$t_head, $($t_rear)*] }
      };
    }

    macro_rules! __for_each_tuple_internal {
      (@invoke $m:ident! $(($i:tt: $T:ident),)+) => {
        $m! { $($i: $T),+ }
      };
      ($m:ident!) => {};
      ($m:ident! $i0:tt: $T0:ident, $($i:tt: $T:ident,)*) => {
        __for_each_tuple_internal! { $m! $($i: $T,)* }
        rev! { __for_each_tuple_internal [@invoke $m!] [($i0: $T0), $(($i: $T),)*] [] }
      };
    }

    macro_rules! for_each_tuple {
      ($m:ident) => {
        __for_each_tuple_internal! {
          $m! 11: T11, 10: T10, 9: T9, 8: T8, 7: T7, 6: T6, 5: T5, 4: T4, 3: T3, 2: T2, 1: T1, 0: T0,
        }
      };
    }
  }

  pub mod algebra {
    pub mod structures {
      pub use self::abelian_group::*;
      pub use self::associative_magma::*;
      pub use self::commutative_magma::*;
      pub use self::group::*;
      pub use self::invertible_magma::*;
      pub use self::magma::*;
      pub use self::monoid::*;
      pub use self::semigroup::*;
      pub use self::unital_magma::*;

      mod abelian_group {
        use super::{CommutativeMagma, Group};

        pub trait AbelianGroup: Group + CommutativeMagma {}

        impl<T: Group + CommutativeMagma> AbelianGroup for T {}
      }

      mod associative_magma {
        use super::Magma;

        pub trait AssociativeMagma: Magma {}

        impl<T> AssociativeMagma for Option<T> where T: AssociativeMagma {}

        impl AssociativeMagma for () {}

        macro_rules! imp {
          ($($i:tt: $T:ident),*) => {
            impl<$($T),*> AssociativeMagma for ($($T,)*)
            where
              $($T: AssociativeMagma,)*
            {
            }
          }
        }

        for_each_tuple! { imp }
      }

      mod commutative_magma {
        use super::Magma;

        pub trait CommutativeMagma: Magma {}

        impl<T> CommutativeMagma for Option<T> where T: CommutativeMagma {}

        impl CommutativeMagma for () {}

        macro_rules! imp {
          ($($i:tt: $T:ident),*) => {
            impl<$($T),*> CommutativeMagma for ($($T,)*)
            where
              $($T: CommutativeMagma,)*
            {
            }
          }
        }

        for_each_tuple! { imp }
      }

      mod group {
        use super::{AssociativeMagma, InvertibleMagma, UnitalMagma};

        pub trait Group: AssociativeMagma + UnitalMagma + InvertibleMagma {}

        impl<T: AssociativeMagma + UnitalMagma + InvertibleMagma> Group for T {}
      }

      mod invertible_magma {
        use super::{Magma, UnitalMagma};

        pub trait InvertibleMagma: Magma + UnitalMagma {
          fn invert(&self) -> Self;

          fn inverse_op(&self, rhs: &Self) -> Self {
            self.op(&rhs.invert())
          }

          fn inverse_op_assign_right(&mut self, rhs: &Self) {
            *self = self.inverse_op(rhs);
          }

          fn inverse_op_assign_left(&mut self, lhs: &Self) {
            *self = lhs.inverse_op(self);
          }
        }

        impl InvertibleMagma for () {
          fn invert(&self) -> Self {
            ()
          }
        }

        macro_rules! imp {
          ($($i:tt: $T:ident),*) => {
            impl<$($T),*> InvertibleMagma for ($($T,)*)
            where
              $($T: InvertibleMagma,)*
            {
              fn invert(&self) -> Self {
                ($(self.$i.invert(),)*)
              }

              fn inverse_op(&self, rhs: &Self) -> Self {
                ($(self.$i.inverse_op(&rhs.$i),)*)
              }

              fn inverse_op_assign_right(&mut self, rhs: &Self) {
                $(self.$i.inverse_op_assign_right(&rhs.$i);)*
              }

              fn inverse_op_assign_left(&mut self, lhs: &Self) {
                $(self.$i.inverse_op_assign_left(&lhs.$i);)*
              }
            }
          }
        }

        for_each_tuple! { imp }
      }

      mod magma {
        pub trait Magma: Clone {
          fn op(&self, rhs: &Self) -> Self;

          fn op_assign_right(&mut self, rhs: &Self) {
            *self = self.op(rhs);
          }

          fn op_assign_left(&mut self, lhs: &Self) {
            *self = lhs.op(self);
          }
        }

        impl<T> Magma for Option<T>
        where
          T: Magma,
        {
          fn op(&self, rhs: &Self) -> Self {
            match (self, rhs) {
              (&Some(ref lhs), &Some(ref rhs)) => Some(lhs.op(rhs)),
              (&Some(ref value), &None) | (&None, &Some(ref value)) => Some(value.clone()),
              (&None, &None) => None,
            }
          }

          fn op_assign_right(&mut self, rhs: &Self) {
            match (self, rhs.as_ref()) {
              (&mut Some(ref mut lhs), Some(rhs)) => lhs.op_assign_right(rhs),
              (lhs @ &mut None, Some(rhs)) => *lhs = Some(rhs.clone()),
              (_, None) => {}
            }
          }

          fn op_assign_left(&mut self, lhs: &Self) {
            match (lhs.as_ref(), self) {
              (Some(lhs), &mut Some(ref mut rhs)) => rhs.op_assign_left(lhs),
              (Some(lhs), rhs @ &mut None) => *rhs = Some(lhs.clone()),
              (None, _) => {}
            }
          }
        }

        impl Magma for () {
          fn op(&self, _rhs: &Self) -> Self {
            ()
          }
        }

        macro_rules! imp {
          ($($i:tt: $T:ident),*) => {
            impl<$($T),*> Magma for ($($T,)*)
            where
              $($T: Magma,)*
            {
              fn op(&self, rhs: &Self) -> Self {
                ($(self.$i.op(&rhs.$i),)*)
              }

              fn op_assign_right(&mut self, rhs: &Self) {
                $(self.$i.op_assign_right(&rhs.$i);)*
              }

              fn op_assign_left(&mut self, lhs: &Self) {
                $(self.$i.op_assign_left(&lhs.$i);)*
              }
            }
          };
        }

        for_each_tuple! { imp }
      }

      mod monoid {
        use super::{AssociativeMagma, UnitalMagma};

        pub trait Monoid: AssociativeMagma + UnitalMagma {}

        impl<T: AssociativeMagma + UnitalMagma> Monoid for T {}
      }

      mod semigroup {
        use super::AssociativeMagma;

        pub trait Semigroup: AssociativeMagma {}

        impl<T: AssociativeMagma> Semigroup for T {}
      }

      mod unital_magma {
        use super::Magma;

        pub trait UnitalMagma: Magma {
          fn identity() -> Self;
        }

        impl<T> UnitalMagma for Option<T>
        where
          T: Magma,
        {
          fn identity() -> Self {
            None
          }
        }

        impl UnitalMagma for () {
          fn identity() -> Self {
            ()
          }
        }

        macro_rules! imp {
          ($($i:tt: $T:ident),*) => {
            impl<$($T),*> UnitalMagma for ($($T,)*)
            where
              $($T: UnitalMagma,)*
            {
              fn identity() -> Self {
                ($($T::identity(),)*)
              }
            }
          }
        }

        for_each_tuple! { imp }
      }
    }
  }

  pub mod byte {
    pub use self::byte_char::*;
    pub use self::byte_str::*;
    pub use self::byte_string::*;
    pub use self::from_byte_str::*;

    mod byte_char {
      use std::fmt::{self, Debug, Display, Formatter};

      #[derive(Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
      pub struct ByteChar(pub u8);

      impl Debug for ByteChar {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          write!(f, "b'{}'", self.0 as char)
        }
      }

      impl Display for ByteChar {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          write!(f, "{}", self.0 as char)
        }
      }
    }

    mod byte_str {
      use spella::byte::{ByteChar, ByteString};
      use std::fmt::{self, Debug, Display, Formatter};
      use std::ops::{Deref, DerefMut};

      #[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
      pub struct ByteStr([ByteChar]);

      macro_rules! cast {
        (mut $x:expr, $($T:ty)=>*) => {
          unsafe { &mut *($x $(as *mut $T)*) }
        };
        ($x:expr, $($T:ty)=>*) => {
          unsafe { &*($x $(as *const $T)*) }
        };
      }

      impl ByteStr {
        pub fn from_bytes(s: &[u8]) -> &Self {
          cast!(s, [u8] => [ByteChar] => ByteStr)
        }

        pub fn from_bytes_mut(s: &mut [u8]) -> &mut Self {
          cast!(mut s, [u8] => [ByteChar] => ByteStr)
        }

        pub fn from_byte_chars(s: &[ByteChar]) -> &Self {
          cast!(s, [ByteChar] => ByteStr)
        }

        pub fn from_byte_chars_mut(s: &mut [ByteChar]) -> &mut Self {
          cast!(mut s, [ByteChar] => ByteStr)
        }

        pub fn as_byte_chars(&self) -> &[ByteChar] {
          &self.0
        }

        pub fn as_byte_chars_mut(&mut self) -> &mut [ByteChar] {
          &mut self.0
        }

        pub fn as_bytes(&self) -> &[u8] {
          cast!(self, ByteStr => [ByteChar] => [u8])
        }

        pub fn as_bytes_mut(&mut self) -> &mut [u8] {
          cast!(mut self, ByteStr => [ByteChar] => [u8])
        }
      }

      impl ToOwned for ByteStr {
        type Owned = ByteString;

        fn to_owned(&self) -> ByteString {
          ByteString::from(self.0.to_owned())
        }
      }

      impl Debug for ByteStr {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          write!(f, "b\"")?;

          for &c in &self.0 {
            write!(f, "{}", c)?;
          }

          write!(f, "\"")
        }
      }

      impl Display for ByteStr {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          for &c in &self.0 {
            write!(f, "{}", c)?;
          }

          Ok(())
        }
      }

      impl Deref for ByteStr {
        type Target = [ByteChar];

        fn deref(&self) -> &[ByteChar] {
          self.as_byte_chars()
        }
      }

      impl DerefMut for ByteStr {
        fn deref_mut(&mut self) -> &mut [ByteChar] {
          self.as_byte_chars_mut()
        }
      }
    }

    mod byte_string {
      use spella::byte::{ByteChar, ByteStr};

      use std::borrow::{Borrow, BorrowMut};
      use std::fmt::{self, Debug, Display, Formatter};
      use std::ops::{Deref, DerefMut};

      #[derive(Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
      pub struct ByteString(Vec<ByteChar>);

      impl ByteString {
        pub fn into_byte_chars(self) -> Vec<ByteChar> {
          self.0
        }

        pub fn as_byte_str(&self) -> &ByteStr {
          ByteStr::from_byte_chars(&self.0)
        }

        pub fn as_mut_byte_str(&mut self) -> &mut ByteStr {
          ByteStr::from_byte_chars_mut(&mut self.0)
        }
      }

      impl From<Vec<ByteChar>> for ByteString {
        fn from(s: Vec<ByteChar>) -> ByteString {
          ByteString(s)
        }
      }

      impl Borrow<ByteStr> for ByteString {
        fn borrow(&self) -> &ByteStr {
          self.as_byte_str()
        }
      }

      impl BorrowMut<ByteStr> for ByteString {
        fn borrow_mut(&mut self) -> &mut ByteStr {
          self.as_mut_byte_str()
        }
      }

      impl Debug for ByteString {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          Debug::fmt(self.as_byte_str(), f)
        }
      }

      impl Display for ByteString {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          Display::fmt(self.as_byte_str(), f)
        }
      }

      impl Deref for ByteString {
        type Target = ByteStr;

        fn deref(&self) -> &ByteStr {
          ByteStr::from_byte_chars(&self.0)
        }
      }

      impl DerefMut for ByteString {
        fn deref_mut(&mut self) -> &mut ByteStr {
          ByteStr::from_byte_chars_mut(&mut self.0)
        }
      }
    }

    mod from_byte_str {
      use spella::byte::{ByteChar, ByteStr, ByteString};

      use std::error::Error;
      use std::fmt::{self, Debug, Display, Formatter};
      use std::str::{self, FromStr, Utf8Error};

      pub trait FromByteStr: Sized {
        type Err;

        fn from_byte_str(s: &ByteStr) -> Result<Self, Self::Err>;
      }

      macro_rules! fn_description {
        () => {
          fn description(&self) -> &str {
            "description() is deprecated; use Display"
          }
        };
      }

      #[derive(Debug)]
      pub struct ParseByteCharError(ParseByteCharErrorKind);

      #[derive(Debug)]
      enum ParseByteCharErrorKind {
        EmptyByteStr,
        TooManyByteChars,
      }

      impl Display for ParseByteCharError {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          use self::ParseByteCharErrorKind::*;

          f.write_str(match self.0 {
            EmptyByteStr => "empty `ByteStr`",
            TooManyByteChars => "too many `ByteChar`s",
          })
        }
      }

      impl Error for ParseByteCharError {
        fn_description! {}
      }

      impl FromByteStr for ByteChar {
        type Err = ParseByteCharError;

        fn from_byte_str(s: &ByteStr) -> Result<Self, Self::Err> {
          use self::ParseByteCharErrorKind::*;

          match s.len() {
            1 => Ok(unsafe { *s.get_unchecked(0) }),
            0 => Err(ParseByteCharError(EmptyByteStr)),
            _ => Err(ParseByteCharError(TooManyByteChars)),
          }
        }
      }

      #[derive(Debug)]
      pub enum ParseByteStringError {}

      impl Display for ParseByteStringError {
        fn fmt(&self, _: &mut Formatter) -> fmt::Result {
          match *self {}
        }
      }

      impl Error for ParseByteStringError {
        fn_description! {}
      }

      impl FromByteStr for ByteString {
        type Err = ParseByteStringError;

        fn from_byte_str(s: &ByteStr) -> Result<Self, Self::Err> {
          Ok(ByteString::from(s.to_vec()))
        }
      }

      pub struct ParseFromStrError<T: FromStr>(ParseFromStrErrorKind<T>);

      enum ParseFromStrErrorKind<T: FromStr> {
        Utf8Error(Utf8Error),
        FromStrError(T::Err),
      }

      impl<T: FromStr> Debug for ParseFromStrError<T>
      where
        T::Err: Debug,
      {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          use self::ParseFromStrErrorKind::*;

          match self.0 {
            Utf8Error(ref err) => f.debug_tuple("Utf8Error").field(err).finish(),
            FromStrError(ref err) => f.debug_tuple("FromStrError").field(err).finish(),
          }
        }
      }

      impl<T: FromStr> Display for ParseFromStrError<T>
      where
        T::Err: Display,
      {
        fn fmt(&self, f: &mut Formatter) -> fmt::Result {
          use self::ParseFromStrErrorKind::*;

          match self.0 {
            Utf8Error(ref err) => write!(f, "{}", err),
            FromStrError(ref err) => write!(f, "{}", err),
          }
        }
      }

      impl<T: FromStr> Error for ParseFromStrError<T>
      where
        T::Err: Debug + Display,
      {
        fn_description! {}
      }

      impl<T: FromStr> FromByteStr for T {
        type Err = ParseFromStrError<T>;

        fn from_byte_str(s: &ByteStr) -> Result<T, Self::Err> {
          use self::ParseFromStrErrorKind::*;

          str::from_utf8(s.as_bytes())
            .map_err(|e| ParseFromStrError(Utf8Error(e)))
            .and_then(|s| s.parse().map_err(|e| ParseFromStrError(FromStrError(e))))
        }
      }
    }
  }

  pub mod io {
    pub use self::scanner::*;

    mod scanner {
      use spella::byte::{ByteStr, FromByteStr};

      use std::io::{self, BufRead};

      #[derive(Debug)]
      pub struct Scanner<R> {
        reader: R,
        buf: Vec<u8>,
        pos: usize,
      }

      const INITIAL_CAPACITY: usize = 32;

      impl<R: BufRead> Scanner<R> {
        pub fn new(reader: R) -> Self {
          Scanner {
            reader: reader,
            buf: Vec::with_capacity(INITIAL_CAPACITY),
            pos: 0,
          }
        }

        pub fn next<T: FromByteStr>(&mut self) -> io::Result<Result<T, T::Err>> {
          self.next_byte_str().map(T::from_byte_str)
        }

        pub fn next_byte_str(&mut self) -> io::Result<&ByteStr> {
          if self.buf.is_empty() {
            self.read_line()?;
          }

          loop {
            match self.buf.get(self.pos) {
              Some(&b' ') => self.pos += 1,
              Some(&b'\n') => self.read_line()?,
              Some(_) => break,
              None => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)),
            }
          }

          let start = self.pos;
          self.pos += 1;

          loop {
            match self.buf.get(self.pos) {
              Some(&b' ') | Some(&b'\n') | None => break,
              Some(_) => self.pos += 1,
            }
          }

          Ok(ByteStr::from_bytes(&self.buf[start..self.pos]))
        }

        fn read_line(&mut self) -> io::Result<()> {
          self.buf.clear();
          self.pos = 0;
          self.reader.read_until(b'\n', &mut self.buf)?;

          Ok(())
        }
      }
    }
  }

  pub mod sequences {
    pub use self::segment_tree::SegmentTree;

    pub mod segment_tree {
      use super::*;
      use spella::algebra::structures::Monoid;

      use std::collections::VecDeque;
      use std::iter::{self, FromIterator};
      use std::mem;
      use std::ops::{Deref, DerefMut, Range};

      #[derive(Clone, PartialEq, Eq, Debug, Hash)]
      pub struct SegmentTree<T> {
        vec: Vec<T>,
        base_len: usize,
        len: usize,
      }

      impl<M: Monoid> FromIterator<M> for SegmentTree<M> {
        fn from_iter<I>(iter: I) -> Self
        where
          I: IntoIterator<Item = M>,
        {
          let iter = iter.into_iter();

          let min_len = iter.size_hint().0;
          let (min_base_len, min_vec_len) = Self::extend_len(min_len);

          let mut deque = VecDeque::with_capacity(min_vec_len);

          if min_base_len > 1 {
            deque.extend(iter::repeat(M::identity()).take(min_base_len - 1));
          }

          deque.extend(iter);

          let len = deque.len() - min_base_len.saturating_sub(1);
          let (base_len, _) = Self::extend_len(len);

          if base_len > min_base_len {
            for identity in iter::repeat(M::identity()).take(base_len - min_base_len) {
              deque.push_front(identity);
            }
          } else if min_base_len > base_len {
            deque.drain(..min_base_len - base_len);
          }

          let mut tree = SegmentTree {
            vec: deque.into(),
            base_len: base_len,
            len: len,
          };

          for node in (1..base_len).rev() {
            tree.recalc(node);
          }

          tree
        }
      }

      impl<M: Monoid> SegmentTree<M> {
        pub fn new(len: usize) -> Self {
          let (base_len, vec_len) = Self::extend_len(len);

          let vec = if vec_len == 0 {
            vec![]
          } else {
            vec![M::identity(); vec_len]
          };

          SegmentTree {
            vec: vec,
            base_len: base_len,
            len: len,
          }
        }

        pub fn len(&self) -> usize {
          self.len
        }

        pub fn get(&self, index: usize) -> &M {
          assert_index(index, self.len());

          self.node(self.node_index(index))
        }

        pub fn get_mut(&mut self, index: usize) -> GetMut<M> {
          assert_index(index, self.len());

          GetMut {
            node: self.node_index(index),
            tree: self,
          }
        }

        pub fn fold(&self, index: Range<usize>) -> M {
          assert_index_range(&index, self.len());

          let mut start = self.node_index(index.start);
          let mut end = self.node_index(index.end);

          let mut lacc = M::identity();
          let mut racc = M::identity();

          while start < end {
            if start & 1 == 1 {
              lacc.op_assign_right(self.node(start));

              start += 1;
            }

            if end & 1 == 1 {
              end -= 1;

              racc.op_assign_left(self.node(end));
            }

            start >>= 1;
            end >>= 1;
          }

          lacc.op(&racc)
        }

        fn extend_len(len: usize) -> (usize, usize) {
          if len == 0 {
            (0, 0)
          } else {
            len
              .checked_next_power_of_two()
              .and_then(|base_len| {
                (base_len - 1)
                  .checked_add(len)
                  .map(|vec_len| (base_len, vec_len))
              })
              .unwrap_or_else(|| panic!("length too large: {:?}", len))
          }
        }

        fn node_index(&self, index: usize) -> usize {
          self.base_len + index
        }

        fn recalc(&mut self, node: usize) {
          let l = node << 1;
          let r = (node << 1) | 1;

          let last = self.vec.len();
          debug_assert_eq!(last, self.node_index(self.len() - 1));

          if l <= last {
            *self.node_mut(node) = if r <= last {
              self.node(l).op(&self.node(r))
            } else {
              self.node(l).clone()
            };
          }
        }

        fn rebuild(&mut self, mut node: usize) {
          while {
            node >>= 1;
            node > 0
          } {
            self.recalc(node);
          }
        }

        fn node(&self, node: usize) -> &M {
          &self.vec[node - 1]
        }

        fn node_mut(&mut self, node: usize) -> &mut M {
          &mut self.vec[node - 1]
        }
      }

      pub struct GetMut<'a, M: 'a + Monoid> {
        tree: &'a mut SegmentTree<M>,
        node: usize,
      }

      impl<'a, M: Monoid> Drop for GetMut<'a, M> {
        fn drop(&mut self) {
          self.tree.rebuild(self.node);
        }
      }

      impl<'a, M: Monoid> Deref for GetMut<'a, M> {
        type Target = M;

        fn deref(&self) -> &M {
          self.tree.node(self.node)
        }
      }

      impl<'a, M: Monoid> DerefMut for GetMut<'a, M> {
        fn deref_mut(&mut self) -> &mut M {
          self.tree.node_mut(self.node)
        }
      }

      impl<'a, M: Monoid> GetMut<'a, M> {
        pub fn update<F>(&mut self, f: F)
        where
          F: FnOnce(M) -> M,
        {
          let value = mem::replace::<M>(self, M::identity());
          mem::replace::<M>(self, f(value));
        }
      }
    }

    use std::ops::{Range, RangeTo};

    macro_rules! assert_index {
      ($cond:expr, $index:expr, $len:expr) => {
        assert!(
          $cond,
          "index out of bounds: the len is {:?} but the index is {:?}",
          $len, $index
        )
      };
    }

    fn assert_index(index: usize, len: usize) {
      assert_index!(index < len, index, len);
    }

    fn assert_index_range(index: &Range<usize>, len: usize) {
      assert!(
        index.start <= index.end,
        "range start is greater than range end: {:?}",
        index
      );
      assert_index!(index.end <= len, index, len);
    }
  }
}

pub mod stopgap {
  use std::fmt::{self, Debug, Display, Formatter};
  use std::hash::{Hash, Hasher};
  use std::iter::{Product, Sum};
  use std::marker::PhantomData;
  use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};

  pub trait Constant<T> {
    fn get() -> T;
  }

  pub enum _1000000007 {}

  impl Constant<u32> for _1000000007 {
    fn get() -> u32 {
      1000000007
    }
  }

  pub struct ModU32<Mod> {
    _phantom: PhantomData<fn() -> Mod>,
    repr: u32,
  }

  impl<Mod: Constant<u32>> Clone for ModU32<Mod> {
    fn clone(&self) -> Self {
      Self::from_repr(self.repr)
    }
  }

  impl<Mod: Constant<u32>> Copy for ModU32<Mod> {}

  impl<Mod: Constant<u32>> PartialEq for ModU32<Mod> {
    fn eq(&self, other: &Self) -> bool {
      self.repr.eq(&other.repr)
    }
  }

  impl<Mod: Constant<u32>> Eq for ModU32<Mod> {}

  impl<Mod: Constant<u32>> Default for ModU32<Mod> {
    fn default() -> Self {
      ModU32::from_repr(u32::default())
    }
  }

  impl<Mod: Constant<u32>> Hash for ModU32<Mod> {
    fn hash<H>(&self, state: &mut H)
    where
      H: Hasher,
    {
      self.repr.hash(state);
    }
  }

  impl<Mod: Constant<u32>> Debug for ModU32<Mod> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
      Debug::fmt(&self.repr, f)
    }
  }

  impl<Mod: Constant<u32>> Display for ModU32<Mod> {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
      Display::fmt(&self.repr, f)
    }
  }

  impl<Mod: Constant<u32>> ModU32<Mod> {
    pub fn new(value: u32) -> Self {
      Self::from_repr(value % Mod::get())
    }

    fn from_repr(repr: u32) -> Self {
      debug_assert!(repr < Mod::get());
      ModU32 {
        _phantom: PhantomData,
        repr: repr,
      }
    }

    pub fn repr(self) -> u32 {
      self.repr
    }

    pub fn inverse(self) -> Self {
      let mut a = self.repr as i64;
      let mut b = Mod::get() as i64;
      let mut u = 1i64;
      let mut v = 0i64;
      while b != 0 {
        let t = a / b;
        a -= t * b;
        ::std::mem::swap(&mut a, &mut b);
        u -= t * v;
        ::std::mem::swap(&mut u, &mut v);
      }
      u %= Mod::get() as i64;
      if u < 0 {
        u += Mod::get() as i64;
      }
      Self::from_repr(u as u32)
    }

    pub fn pow(mut self, mut n: u32) -> Self {
      let mut acc = ModU32::from_repr(1);
      while n > 0 {
        if n % 2 == 1 {
          acc *= self;
        }
        self *= self;
        n /= 2;
      }
      acc
    }
  }

  impl<Mod: Constant<u32>> Add for ModU32<Mod> {
    type Output = Self;

    fn add(mut self, rhs: Self) -> Self {
      self += rhs;
      self
    }
  }

  impl<Mod: Constant<u32>> AddAssign for ModU32<Mod> {
    fn add_assign(&mut self, rhs: Self) {
      self.repr += rhs.repr;
      if self.repr >= Mod::get() {
        self.repr -= Mod::get();
      }
    }
  }

  impl<Mod: Constant<u32>> Sub for ModU32<Mod> {
    type Output = Self;

    fn sub(mut self, rhs: Self) -> Self {
      self -= rhs;
      self
    }
  }

  impl<Mod: Constant<u32>> SubAssign for ModU32<Mod> {
    fn sub_assign(&mut self, rhs: Self) {
      if self.repr < rhs.repr {
        self.repr += Mod::get();
      }
      self.repr -= rhs.repr;
    }
  }

  impl<Mod: Constant<u32>> Mul for ModU32<Mod> {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
      Self::from_repr((self.repr as u64 * rhs.repr as u64 % Mod::get() as u64) as u32)
    }
  }

  impl<Mod: Constant<u32>> MulAssign for ModU32<Mod> {
    fn mul_assign(&mut self, rhs: Self) {
      *self = *self * rhs;
    }
  }

  impl<Mod: Constant<u32>> Div for ModU32<Mod> {
    type Output = Self;

    fn div(self, rhs: Self) -> Self {
      self * rhs.inverse()
    }
  }

  impl<Mod: Constant<u32>> DivAssign for ModU32<Mod> {
    fn div_assign(&mut self, rhs: Self) {
      *self *= rhs.inverse();
    }
  }

  impl<Mod: Constant<u32>> Sum for ModU32<Mod> {
    fn sum<I>(iter: I) -> Self
    where
      I: Iterator<Item = Self>,
    {
      let mut acc = ModU32::from_repr(0);
      for x in iter {
        acc += x;
      }
      acc
    }
  }

  impl<Mod: Constant<u32>> Product for ModU32<Mod> {
    fn product<I>(iter: I) -> Self
    where
      I: Iterator<Item = Self>,
    {
      let mut acc = ModU32::from_repr(1);
      for x in iter {
        acc *= x;
      }
      acc
    }
  }

  pub fn mod_pow<Mod: Constant<u32>>(base: u32, n: u32) -> ModU32<Mod> {
    ModU32::new(base).pow(n)
  }

  pub fn mod_binomial<Mod: Constant<u32>>(mut n: u32, mut k: u32) -> ModU32<Mod> {
    let mut acc = ModU32::from_repr(1);
    while k != 0 {
      {
        let n = n % Mod::get();
        let k = k % Mod::get();
        if n < k {
          return ModU32::from_repr(0);
        }
        acc *= (n - k + 1..n + 1).map(ModU32::from_repr).product();
        acc /= (1..k + 1).map(ModU32::from_repr).product();
      }
      n /= Mod::get();
      k /= Mod::get();
    }
    acc
  }
}

#[allow(unused_imports)]
use stopgap::*;

mod prelude {
  pub use spella::byte::{ByteChar, ByteStr, ByteString};
  pub use std::collections::*;
  pub use std::io::prelude::*;
  pub use std::iter::FromIterator;
  pub use std::marker::PhantomData;
  pub use std::num::Wrapping;
  pub use std::ops::{Range, RangeFrom, RangeTo};
  pub use std::{cell, cmp, f64, i32, i64, isize, iter, mem, rc, str, time, u32, u64, usize};
}

use prelude::*;

const CUSTOM_STACK_SIZE_MEBIBYTES: Option<usize> = None;

fn main() {
  fn exec_solver() {
    let stdin = std::io::stdin();
    let stdout = std::io::stdout();
    #[cfg(not(debug_assertions))]
    let mut writer = std::io::BufWriter::new(stdout.lock());
    #[cfg(debug_assertions)]
    let mut writer = stdout.lock();
    solve(stdin.lock(), &mut writer);
    writer.flush().unwrap();
  }

  if let Some(stack_size_mebibytes) = CUSTOM_STACK_SIZE_MEBIBYTES {
    std::thread::Builder::new()
      .name("exec_solver".to_owned())
      .stack_size(stack_size_mebibytes * 1024 * 1024)
      .spawn(exec_solver)
      .unwrap()
      .join()
      .unwrap();
  } else {
    exec_solver();
  }
}

fn solve<R: BufRead, W: Write>(reader: R, mut writer: W) {
  let mut _scanner = spella::io::Scanner::new(reader);

  #[allow(unused_macros)]
  macro_rules! scan {
    ($T:ty) => {
      _scanner.next::<$T>().unwrap().unwrap()
    };
    ($($T:ty),+) => {
      ($(scan!($T)),+)
    };
    ($($T:ty),+; $n:expr $(; $m:expr)*) => {{
      (0..$n).map(|_| scan!($($T),+ $(; $m)*)).collect::<Vec<_>>()
    }};
  }

  #[allow(unused_macros)]
  macro_rules! scan_iter {
    ($($T:ty),+; $n:expr) => {
      (0..$n).map(|_| scan!($($T),+))
    };
  }

  #[allow(unused_macros)]
  macro_rules! print {
    ($fmt:expr) => {
      write!(writer, $fmt).unwrap()
    };
    ($fmt:expr, $($arg:tt)*) => {
      write!(writer, $fmt, $($arg)*).unwrap()
    };
  }

  #[allow(unused_macros)]
  macro_rules! println {
    ($fmt:expr) => {
      writeln!(writer, $fmt).unwrap()
    };
    ($fmt:expr, $($arg:tt)*) => {
      writeln!(writer, $fmt, $($arg)*).unwrap()
    };
  }

  #[allow(unused_macros)]
  macro_rules! eprint {
    ($fmt:expr) => {
      #[cfg(debug_assertions)]
      write!(std::io::stderr(), $fmt).unwrap()
    };
    ($fmt:expr, $($arg:tt)*) => {
      #[cfg(debug_assertions)]
      write!(std::io::stderr(), $fmt, $($arg)*).unwrap()
    };
  }

  #[allow(unused_macros)]
  macro_rules! eprintln {
    ($fmt:expr) => {
      #[cfg(debug_assertions)]
      writeln!(std::io::stderr(), $fmt).unwrap()
    };
    ($fmt:expr, $($arg:tt)*) => {
      #[cfg(debug_assertions)]
      writeln!(std::io::stderr(), $fmt, $($arg)*).unwrap()
    };
  }

  #[allow(unused_macros)]
  macro_rules! dbg {
    ($($x:expr),+) => {{
      eprintln!(concat!("[{}:{}] ", $(stringify!($x), " = {:?}; "),+), file!(), line!(), $($x),+);
    }};
  }

  use spella::algebra::structures::*;
  use spella::sequences::SegmentTree;

  #[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug)]
  struct M(u32);

  impl M {
    fn from_byte_char(c: ByteChar) -> Self {
      M(1 << (c.0 - b'a'))
    }
  }

  impl Magma for M {
    fn op(&self, rhs: &Self) -> Self {
      M(self.0 | rhs.0)
    }
  }

  impl AssociativeMagma for M {}

  impl UnitalMagma for M {
    fn identity() -> Self {
      M(0)
    }
  }

  let _n = scan!(usize);
  let s = scan!(ByteString);
  let q = scan!(usize);

  let mut segtree = SegmentTree::from_iter(s.into_byte_chars().into_iter().map(M::from_byte_char));

  for _ in 0..q {
    match scan!(u8) {
      1 => {
        let (i, c) = scan!(usize, ByteChar);
        *segtree.get_mut(i - 1) = M::from_byte_char(c);
      }
      2 => {
        let (l, r) = scan!(usize, usize);
        println!("{}", segtree.fold(l - 1..r).0.count_ones());
      }
      _ => unreachable!(),
    }
  }
}