#include <bits/stdc++.h>
using namespace std;
struct LazyContext {
  LazyContext() { iota(conv, conv + 10, 0); }
  LazyContext(int l, int r) {
    iota(conv, conv + 10, 0);
    conv[l] = r;
  }
  void reset() { iota(conv, conv + 10, 0); }
  void operator+=(LazyContext &o) {
    int aux[10];
    memcpy(aux, conv, sizeof conv);
    for (int i = 0; i < 10; ++i) {
      conv[i] = o.conv[aux[i]];
    }
  }
  int conv[10];
};
struct Node {
  Node() { memset(contri, 0, sizeof contri); }
  Node(int u) {
    memset(contri, 0, sizeof contri);
    int pot = 1;
    while (u) {
      contri[u % 10] += pot;
      pot *= 10;
      u /= 10;
    }
  }
  Node(Node &l, Node &r) {
    for (int i = 0; i < 10; ++i) {
      contri[i] = l.contri[i] + r.contri[i];
    }
  }
  void apply(LazyContext &lazy) {
    long long aux[10];
    memset(aux, 0, sizeof aux);
    for (int i = 0; i < 10; ++i) {
      aux[lazy.conv[i]] += contri[i];
    }
    memcpy(contri, aux, sizeof contri);
  }
  long long ans() {
    long long ret = 0;
    for (long long i = 1; i < 10; ++i) {
      ret += i * contri[i];
    }
    return ret;
  }
  long long contri[10];
};
template <class i_t, class e_t, class lazy_cont = int>
class SegmentTree {
 public:
  void init(std::vector<e_t> base) {
    n = base.size();
    h = 0;
    while ((1 << h) < n) h++;
    tree.resize(2 * n);
    dirty.assign(n, false);
    lazy.resize(n);
    for (int i = 0; i < n; i++) {
      tree[i + n] = i_t(base[i]);
    }
    for (int i = n - 1; i > 0; i--) {
      tree[i] = i_t(tree[i + i], tree[i + i + 1]);
      lazy[i].reset();
    }
  }
  i_t qry(int l, int r) {
    if (l >= r) return i_t();
    l += n, r += n;
    push(l);
    push(r - 1);
    i_t lp, rp;
    for (; l < r; l /= 2, r /= 2) {
      if (l & 1) lp = i_t(lp, tree[l++]);
      if (r & 1) rp = i_t(tree[--r], rp);
    }
    return i_t(lp, rp);
  }
  void upd(int l, int r, lazy_cont lc) {
    if (l >= r) return;
    l += n, r += n;
    push(l);
    push(r - 1);
    int l0 = l, r0 = r;
    for (; l < r; l /= 2, r /= 2) {
      if (l & 1) apply(l++, lc);
      if (r & 1) apply(--r, lc);
    }
    build(l0);
    build(r0 - 1);
  }

 private:
  int n, h;
  std::vector<bool> dirty;
  std::vector<i_t> tree;
  std::vector<lazy_cont> lazy;
  void apply(int p, lazy_cont &lc) {
    tree[p].apply(lc);
    if (p < n) {
      dirty[p] = true;
      lazy[p] += lc;
    }
  }
  void push(int p) {
    for (int s = h; s > 0; s--) {
      int i = p >> s;
      if (dirty[i]) {
        apply(i + i, lazy[i]);
        apply(i + i + 1, lazy[i]);
        lazy[i].reset();
        dirty[i] = false;
      }
    }
  }
  void build(int p) {
    for (p /= 2; p > 0; p /= 2) {
      tree[p] = i_t(tree[p + p], tree[p + p + 1]);
      if (dirty[p]) {
        tree[p].apply(lazy[p]);
      }
    }
  }
};
int read() {
  int x = 0;
  int sign = 0;
  int c = getchar();
  for (; !isdigit(c); c = getchar()) {
    sign |= c == '-';
  }
  for (; isdigit(c); c = getchar()) {
    x = x * 10 + c - '0';
  }
  return sign ? -x : x;
}
void write(long long x) {
  if (x < 0) {
    putchar('-');
    x = -x;
  }
  if (x / 10) {
    write(x / 10);
  }
  putchar(x % 10 + '0');
}
int main() {
  int n = read(), q = read();
  vector<int> arr(n);
  for (int i = 0; i < n; ++i) {
    arr[i] = read();
  }
  SegmentTree<Node, int, LazyContext> st;
  st.init(arr);
  while (q--) {
    int type = read(), l = read(), r = read();
    if (type == 1) {
      int x = read(), y = read();
      st.upd(l - 1, r, LazyContext(x, y));
    } else {
      write(st.qry(l - 1, r).ans());
      putchar('\n');
    }
  }
  return 0;
}
