#include <bits/stdc++.h>
using namespace std;
const int __SIZE = 1 << 18;
char ibuf[__SIZE], *iS, *iT;
template <typename T>
inline void read(T &x) {
  char ch, t = 0;
  x = 0;
  while (!isdigit(ch = (iS == iT
                            ? (iT = (iS = ibuf) + fread(ibuf, 1, __SIZE, stdin),
                               (iS == iT ? EOF : *iS++))
                            : *iS++)))
    t |= ch == '-';
  while (isdigit(ch))
    x = x * 10 + (ch ^ 48),
    ch = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, __SIZE, stdin),
                      (iS == iT ? EOF : *iS++))
                   : *iS++);
  x = t ? -x : x;
}
inline char read_alpha() {
  char c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, __SIZE, stdin),
                        (iS == iT ? EOF : *iS++))
                     : *iS++);
  while (!isalpha(c) && c != EOF)
    c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, __SIZE, stdin),
                     (iS == iT ? EOF : *iS++))
                  : *iS++);
  return c;
}
inline int read_int() {
  int x;
  return read(x), x;
}
inline long long read_ll() {
  long long x;
  return read(x), x;
}
template <typename T>
inline void chkmin(T &a, T b) {
  a = a < b ? a : b;
}
template <typename T>
inline void chkmax(T &a, T b) {
  a = a > b ? a : b;
}
const int MAXN = 100010;
const long long inf = 100000000000000000LL;
const long long pw[] = {1LL,
                        42LL,
                        1764LL,
                        74088LL,
                        3111696LL,
                        130691232LL,
                        5489031744LL,
                        230539333248LL,
                        9682651996416LL,
                        406671383849472LL,
                        17080198121677824LL,
                        717368321110468608LL,
                        1000000000000000000LL};
set<int> pos;
long long a[MAXN];
long long ad[MAXN];
int n;
inline long long fdv(long long x) { return *lower_bound(pw, pw + 12, x); }
struct Segment_Tree {
  struct Node {
    long long v, tg, tv;
    Node() : v(inf), tg(0), tv(0) {}
  } T[MAXN << 2];
  inline void pushup(int x) { T[x].v = min(T[(x << 1)].v, T[(x << 1 | 1)].v); }
  inline void pushdown(int x) {
    if (!T[x].tg && !T[x].tv) return;
    Node &L = T[(x << 1)], &R = T[(x << 1 | 1)];
    if (T[x].tg) {
      L.v = L.tg = T[x].tg, L.tv = 0;
      R.v = R.tg = T[x].tg, R.tv = 0;
      T[x].tg = 0;
    }
    if (T[x].tv) {
      L.v += T[x].tv, L.tv += T[x].tv;
      R.v += T[x].tv, R.tv += T[x].tv;
      T[x].tv = 0;
    }
  }
  inline void build(int x, int l, int r) {
    if (l == r) return ad[l] = fdv(a[l]), T[x].v = ad[l] - a[l], void();
    int mid = (l + r) >> 1;
    build((x << 1), l, mid), build((x << 1 | 1), mid + 1, r), pushup(x);
  }
  inline void Assign(int x, int l, int r, int L, int R) {
    if (L <= l && r <= R) return T[x].v = T[x].tg = inf, T[x].tv = 0, void();
    int mid = (l + r) >> 1;
    pushdown(x);
    if (L <= mid) Assign((x << 1), l, mid, L, R);
    if (mid < R) Assign((x << 1 | 1), mid + 1, r, L, R);
    pushup(x);
  }
  inline void Modify(int x, int l, int r, int p, long long v) {
    if (l == r) return ad[l] = fdv(v), T[x].v = ad[l] - v, void();
    int mid = (l + r) >> 1;
    pushdown(x);
    p <= mid ? Modify((x << 1), l, mid, p, v)
             : Modify((x << 1 | 1), mid + 1, r, p, v);
    pushup(x);
  }
  inline void Dec(int x, int l, int r, int L, int R, long long v) {
    if (L <= l && r <= R) return T[x].v -= v, T[x].tv -= v, void();
    int mid = (l + r) >> 1;
    pushdown(x);
    if (L <= mid) Dec((x << 1), l, mid, L, R, v);
    if (mid < R) Dec((x << 1 | 1), mid + 1, r, L, R, v);
    pushup(x);
  }
  inline long long Qm(int x, int l, int r) {
    if (T[x].v >= 0) return T[x].v;
    if (l == r) {
      T[x].v = ad[l] - T[x].v;
      ad[l] = fdv(T[x].v);
      T[x].v = ad[l] - T[x].v;
      return T[x].v;
    }
    int mid = (l + r) >> 1;
    pushdown(x);
    Qm((x << 1), l, mid), Qm((x << 1 | 1), mid + 1, r);
    pushup(x);
    return T[x].v;
  }
  inline long long Qval(int x, int l, int r, int p) {
    if (l == r) return ad[p] - T[x].v;
    int mid = (l + r) >> 1;
    pushdown(x);
    return p <= mid ? Qval((x << 1), l, mid, p)
                    : Qval((x << 1 | 1), mid + 1, r, p);
  }
  inline void Split(int p) {
    int vp = *pos.lower_bound(p);
    if (vp == p) return;
    ad[p] = ad[vp], pos.insert(p);
    Modify(1, 1, n, p, Qval(1, 1, n, vp));
  }
} seg;
int main() {
  n = read_int();
  int q = read_int();
  for (int i = 1; i <= n; i++) pos.insert(i), a[i] = read_int();
  seg.build(1, 1, n);
  for (int i = 1; i <= q; i++) {
    int opt = read_int();
    if (opt == 1) {
      int p = read_int();
      printf("%lld\n", seg.Qval(1, 1, n, *pos.lower_bound(p)));
    } else {
      int l = read_int(), r = read_int(), v = read_int();
      if (l > 1) seg.Split(l - 1);
      seg.Split(r);
      if (opt == 2) {
        pos.erase(pos.lower_bound(l), pos.lower_bound(r));
        if (l < r) seg.Assign(1, 1, n, l, r - 1);
        seg.Modify(1, 1, n, r, v);
      } else
        for (seg.Dec(1, 1, n, l, r, v); !seg.Qm(1, 1, n);
             seg.Dec(1, 1, n, l, r, v))
          ;
    }
  }
  return 0;
}
