#include <algorithm>
#include <cstdint>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <deque>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <cfloat>
#include <bitset>

using namespace std;

using lint=int64_t;
using uint=uint32_t;
using ulint=uint64_t;

template<class T>
using vector2d=vector<vector<T>>;

template<class T>
bool UpdateMax(T &a, const T &b){
  if(a<b){
    a=b;
    return true;
  }else{
    return false;
  }
}

template<class T>
bool UpdateMin(T &a, const T &b){
  if(a>b){
    a=b;
    return true;
  }else{
    return false;
  }
}

template <class T>
void OutVec(const vector<T>& vec){
  for(int i = 0; i < vec.size() - 1; ++i){
    cout<<vec[i]<<" ";
  }
  cout<<vec.back()<<endl;
}

template <class T>
void OutVec2d(const vector2d<T>& vec){
  for(auto v:vec){
    OutVec(v);
  }
}

template<typename Monoid>
class SegmentTree{
private:
  int                 range_;
  Monoid              identity_;
  std::vector<Monoid> tree_;

  virtual Monoid Operate(const Monoid& a, const Monoid& b)=0;

  Monoid InternalOperate(const Monoid& a, const Monoid& b){
    if(a==identity_){
      return b;
    }else if(b==identity_){
      return a;
    }else{
      return Operate(a,b);
    }
  }

  int Parent(const int child) const{
    return (child - 1) / 2;
  }

  int LeftChild(const int parent) const{
    return parent * 2 + 1;
  }

  int RightChild(const int parent) const{
    return parent * 2 + 2;
  }

  Monoid GetResult(int query_l, int query_r, int node, int l, int r){
    if(r <= query_l || query_r <= l){
      return identity_;
    }else if(query_l <= l && r <= query_r){
      return tree_[node];
    }else{
      Monoid vl = GetResult(query_l, query_r, LeftChild(node), l,
                            (l + r) / 2);
      Monoid vr = GetResult(query_l, query_r, RightChild(node),
                            (l + r) / 2, r);
      return InternalOperate(vl, vr);
    }

  }

public:

  /// \brief construct the segment tree.
  /// \param identity the element e s.t. a*e = e*a = a  (単位元)
  /// \param v tree initializer
  //FIXME: コンストラクタ中で仮想関数を使わないようにする
  SegmentTree(const Monoid& identity, const int size): identity_(
      identity){
    int sz = size;
    range_ = 1;
    while(range_ < sz){
      range_ *= 2;
    }
    tree_.resize(2 * range_ - 1, identity);

  }

  void Init(const std::vector<Monoid>& v){
    for(int i = 0; i < v.size(); i++){
      tree_[i + range_ - 1] = v[i];
    }
    for(int i = range_ - 2; i >= 0; i--){
      tree_[i] = InternalOperate(tree_[LeftChild(i)], tree_[RightChild(i)]);
    }
  }

  /// \brief set the value and refresh the tree
  /// \param pos position
  /// \param val value
  void SetValue(int pos, const Monoid& val){
    pos += (range_ - 1);

    tree_[pos] = val;
    while(pos > 0){
      pos = Parent(pos);
      tree_[pos] =
          InternalOperate(tree_[LeftChild(pos)], tree_[RightChild(pos)]);
    }
  }

  /// \brief [l,r)に対して演算をした結果を返す
  /// \param l 範囲左端(lを含む)
  /// \param r 範囲右端(rを含まない)
  /// \return result

  Monoid GetResult(int l, int r){
    return GetResult(l, r, 0, 0, range_);
  }
};

// example of implementation

class RMQTree:public SegmentTree<int64_t>{
  int64_t Operate(const int64_t& a, const int64_t& b) override {
    return std::min(a,b);
  }
public:
  RMQTree(const int64_t& identity, const int n):SegmentTree(identity,n){}
};

typedef std::bitset<30> bs;

class Tree:public SegmentTree<bs>{
  bs Operate(const bs& a,const bs& b){
    return a|b;
  }
public:
  Tree(const bs& identity, const int n):SegmentTree(identity,n){}
};

int main(){
  cout << std::fixed << std::setprecision(16);
  cin.tie(nullptr);
  std::ios::sync_with_stdio(false);

  int n;
  cin>>n;
  string s;
  cin>>s;
  Tree tree(bs(0),n+1);
  for(int i=0;i<n;i++){
    bs init(0);
    char c=s[i];
    init[c-'a']=true;
    tree.SetValue(i,init);
  }
  int q;
  cin>>q;
  for(int i=0;i<q;i++){
    int type;
    cin>>type;
    if(type==1){
      int p;
      char c;
      cin>>p>>c;
      bs  val(0);
      val[c-'a']=true;
      tree.SetValue(p-1,val);
    }else{
      int l,r;
      cin>>l>>r;
      bs result=tree.GetResult(l-1,r);
      cout<<result.count()<<endl;
    }
  }

  return 0;
}




Measured memory_bytes: 9244