#include <bits/stdc++.h>
using namespace std;
template <class T>
inline void rread(T& num) {
  num = 0;
  T f = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') num = num * 10 + ch - '0', ch = getchar();
  num *= f;
}
const int maxn = 1e5 + 5, maxpow = 9;
const long long inf = 1e18;
int n, m;
long long a[maxn];
vector<long long> bin;
inline void Prework() {
  long long now = 1;
  for (int(i) = (0); (i) < (maxpow); (i)++) bin.push_back(now), now *= 42;
}
inline long long GetToNxt(long long x) {
  int tmp = lower_bound(bin.begin(), bin.end(), x) - bin.begin();
  if (tmp == maxpow) return inf;
  return bin[tmp] - x;
}
int root;
namespace Treap {
int ndtot;
struct TreapNode {
  int l, r, len, sz;
  long long val, tonxt, mini, tag;
} T[maxn];
vector<int> pool;
inline int NewNode(long long val, int len) {
  int x;
  if (((pool).size()))
    x = pool.back(), pool.pop_back();
  else
    x = ++ndtot;
  (T[(x)].l) = (T[(x)].r) = (T[(x)].tag) = 0;
  (T[(x)].val) = val;
  (T[(x)].sz) = (T[(x)].len) = len;
  (T[(x)].tonxt) = (T[(x)].mini) = GetToNxt(val);
  return x;
}
inline void Update(int x) {
  (T[(x)].sz) = (T[(x)].len) + (T[((T[(x)].l))].sz) + (T[((T[(x)].r))].sz);
  (T[(x)].mini) =
      min((T[(x)].tonxt), min((T[((T[(x)].l))].mini), (T[((T[(x)].r))].mini)));
}
inline int Build(int l, int r) {
  if (l > r) return 0;
  int x = NewNode(a[((l + r) >> 1)], 1);
  (T[(x)].l) = Build(l, ((l + r) >> 1) - 1);
  (T[(x)].r) = Build(((l + r) >> 1) + 1, r);
  Update(x);
  return x;
}
inline void AddVal(int x, long long num) {
  if (!x) return;
  (T[(x)].tag) += num;
  (T[(x)].val) += num;
  (T[(x)].tonxt) -= num;
  (T[(x)].mini) -= num;
}
inline void PushDown(int x) {
  if (!x || !(T[(x)].tag)) return;
  AddVal((T[(x)].l), (T[(x)].tag));
  AddVal((T[(x)].r), (T[(x)].tag));
  (T[(x)].tag) = 0;
}
inline int Rnd(int x, int y) {
  return rand() % ((T[(x)].sz) + (T[(y)].sz)) < (T[(x)].sz);
}
inline int Merge(int x, int y) {
  if (!x || !y) return x + y;
  PushDown(x);
  PushDown(y);
  if (Rnd(x, y)) {
    (T[(x)].r) = Merge((T[(x)].r), y);
    Update(x);
    return x;
  } else {
    (T[(y)].l) = Merge(x, (T[(y)].l));
    Update(y);
    return y;
  }
}
inline pair<int, int> Split(int x, int len) {
  if (!x) return make_pair(0, 0);
  PushDown(x);
  if ((T[((T[(x)].l))].sz) >= len) {
    pair<int, int> y = Split((T[(x)].l), len);
    (T[(x)].l) = y.second;
    Update(x);
    return make_pair(y.first, x);
  }
  len -= (T[((T[(x)].l))].sz);
  if (len < (T[(x)].len)) {
    int x1 = NewNode((T[(x)].val), len),
        x2 = NewNode((T[(x)].val), (T[(x)].len) - len);
    (T[(x1)].l) = (T[(x)].l);
    (T[(x2)].r) = (T[(x)].r);
    Update(x1);
    Update(x2);
    pool.push_back(x);
    return make_pair(x1, x2);
  }
  len -= (T[(x)].len);
  pair<int, int> z = Split((T[(x)].r), len);
  (T[(x)].r) = z.first;
  Update(x);
  return make_pair(x, z.second);
}
inline long long QueryVal(int x) {
  long long res;
  pair<int, int> b = Split(root, x), a = Split(b.first, x - 1);
  res = (T[(a.second)].val);
  b.first = Merge(a.first, a.second);
  root = Merge(b.first, b.second);
  return res;
}
inline void Recycle(int x) {
  if (!x) return;
  Recycle((T[(x)].l));
  pool.push_back(x);
  Recycle((T[(x)].r));
}
inline void SetVal(int l, int r, long long val) {
  pair<int, int> b = Split(root, r), a = Split(b.first, l - 1);
  Recycle(a.second);
  int x = NewNode(val, r - l + 1);
  b.first = Merge(a.first, x);
  root = Merge(b.first, b.second);
}
inline void FixMini(int x) {
  if (!x) return;
  PushDown(x);
  if ((T[(x)].tonxt) == (T[(x)].mini)) {
    (T[(x)].tonxt) = GetToNxt((T[(x)].val));
    Update(x);
    return;
  }
  if ((T[((T[(x)].l))].mini) < (T[((T[(x)].r))].mini))
    FixMini((T[(x)].l));
  else
    FixMini((T[(x)].r));
  Update(x);
}
inline void Print(int x) {
  if (!x) return;
  Print((T[(x)].l));
  cerr << (T[(x)].val) << "(" << (T[(x)].tonxt) << ") ";
  Print((T[(x)].r));
}
inline void AddVal(int l, int r, long long x) {
  pair<int, int> b = Split(root, r), a = Split(b.first, l - 1);
  AddVal(a.second, x);
  while (1) {
    while ((T[(a.second)].mini) < 0) FixMini(a.second);
    if ((T[(a.second)].mini) > 0) break;
    AddVal(a.second, x);
  }
  b.first = Merge(a.first, a.second);
  root = Merge(b.first, b.second);
}
inline void Init() { (T[(0)].mini) = inf; }
}  // namespace Treap
inline void judge() {
  freopen("input.txt", "r", stdin);
  freopen("output.txt", "w", stdout);
}
int main() {
  Prework();
  Treap::Init();
  rread(n);
  rread(m);
  for (int(i) = (1); (i) <= (n); (i)++) rread(a[i]);
  root = Treap::Build(1, n);
  while (m--) {
    int opt;
    rread(opt);
    if (opt == 1) {
      int x;
      rread(x);
      printf("%lld\n", Treap::QueryVal(x));
    } else if (opt == 2) {
      int l, r;
      long long x;
      rread(l);
      rread(r);
      rread(x);
      Treap::SetVal(l, r, x);
    } else if (opt == 3) {
      int l, r;
      long long x;
      rread(l);
      rread(r);
      rread(x);
      Treap::AddVal(l, r, x);
    }
  }
  return 0;
}
