#include <bits/stdc++.h>
using namespace std;
template <typename tp>
inline void read(tp& x) {
  x = 0;
  char tmp;
  bool key = 0;
  for (tmp = getchar(); !isdigit(tmp); tmp = getchar()) key = (tmp == '-');
  for (; isdigit(tmp); tmp = getchar()) x = (x << 3) + (x << 1) + (tmp ^ '0');
  if (key) x = -x;
}
template <typename tp>
inline void ckmn(tp& x, tp y) {
  x = x < y ? x : y;
}
template <typename tp>
inline void ckmx(tp& x, tp y) {
  x = x < y ? y : x;
}
const long long LLINF = (long long)1e18;
const int N = 100010, MP = 20;
int n, q, sta[N];
long long rec[MP], val[N];
struct node {
  long long mn;
  long long rv;
  long long tag;
  int rec;
} t[N << 2];
void puttag(int x, long long v) {
  t[x].tag += v;
  t[x].mn -= v;
  t[x].rv += v;
}
void putrec(int x) {
  t[x].rec = 1;
  t[x].rv = t[x].mn = LLINF;
  t[x].tag = 0;
}
void push_down(int x) {
  if (t[x].tag) {
    puttag(x << 1, t[x].tag);
    puttag(x << 1 | 1, t[x].tag);
    t[x].tag = 0;
  }
  if (t[x].rec) {
    putrec(x << 1);
    putrec(x << 1 | 1);
    t[x].rec = 0;
  }
}
void push_up(int x) {
  t[x].mn = min(t[x << 1].mn, t[x << 1 | 1].mn);
  t[x].rv = t[x << 1 | 1].rv;
  if (t[x].rv >= LLINF) t[x].rv = t[x << 1].rv;
}
long long query(int p, int x = 1, int lp = 1, int rp = n) {
  if (lp == rp) return t[x].rv;
  push_down(x);
  int mid = (lp + rp) >> 1;
  if (p <= mid) return query(p, x << 1, lp, mid);
  long long tmp = query(p, x << 1 | 1, mid + 1, rp);
  if (tmp >= LLINF)
    return t[x << 1].rv;
  else
    return tmp;
}
long long askmn(int l, int r, int x = 1, int lp = 1, int rp = n) {
  if (l > rp || lp > r) return LLINF;
  if (lp >= l && rp <= r) return t[x].mn;
  int mid = (lp + rp) >> 1;
  push_down(x);
  return min(askmn(l, r, x << 1, lp, mid),
             askmn(l, r, x << 1 | 1, mid + 1, rp));
}
void modify(int l, int r, long long v, int x = 1, int lp = 1, int rp = n) {
  if (l > rp || lp > r) return;
  if (lp >= l && rp <= r) {
    puttag(x, v);
    return;
  }
  int mid = (lp + rp) >> 1;
  push_down(x);
  modify(l, r, v, x << 1, lp, mid), modify(l, r, v, x << 1 | 1, mid + 1, rp);
  push_up(x);
}
void doit(int x = 1, int lp = 1, int rp = n) {
  if (t[x].mn >= 0) return;
  if (lp == rp) {
    while (t[x].mn < 0) {
      ++sta[lp];
      t[x].mn = rec[sta[lp]] - t[x].rv;
    }
    return;
  }
  int mid = (lp + rp) >> 1;
  push_down(x);
  doit(x << 1, lp, mid);
  doit(x << 1 | 1, mid + 1, rp);
  push_up(x);
}
void fill(int l, int r, int x = 1, int lp = 1, int rp = n) {
  if (l > rp || lp > r) return;
  if (lp >= l && rp <= r) {
    putrec(x);
    return;
  }
  int mid = (lp + rp) >> 1;
  push_down(x);
  fill(l, r, x << 1, lp, mid);
  fill(l, r, x << 1 | 1, mid + 1, rp);
  push_up(x);
}
void setval(int p, long long v, int x = 1, int lp = 1, int rp = n) {
  if (lp == rp) {
    t[x].rv = v;
    t[x].tag = 0, t[x].rec = 0;
    t[x].mn = rec[0] - v;
    sta[lp] = 0;
    return;
  }
  int mid = (lp + rp) >> 1;
  push_down(x);
  if (p <= mid)
    setval(p, v, x << 1, lp, mid);
  else
    setval(p, v, x << 1 | 1, mid + 1, rp);
  push_up(x);
}
void build(int x = 1, int lp = 1, int rp = n) {
  t[x].tag = t[x].rec = 0;
  if (lp == rp) {
    t[x].rv = val[lp];
    t[x].mn = rec[sta[lp]] - val[lp];
    return;
  }
  int mid = (lp + rp) >> 1;
  build(x << 1, lp, mid);
  build(x << 1 | 1, mid + 1, rp);
  push_up(x);
}
int main() {
  int tp, x, y, z;
  read(n), read(q);
  for (int i = (1); i <= (n); ++i) read(val[i]);
  rec[0] = 1;
  for (int i = 1; rec[i - 1] <= LLINF / 42; ++i) rec[i] = rec[i - 1] * 42;
  build();
  for (int i = (1); i <= (q); ++i) {
    read(tp);
    if (tp == 1) {
      read(x);
      printf("%lld\n", query(x));
    } else if (tp == 2) {
      read(x), read(y), read(z);
      if (y < n) setval(y + 1, query(y + 1));
      setval(x, z);
      if (x < y) fill(x + 1, y);
    } else {
      read(x), read(y), read(z);
      setval(x, query(x));
      if (y < n) setval(y + 1, query(y + 1));
      while (true) {
        modify(x, y, z);
        doit();
        if (askmn(x, y) > 0) break;
      }
    }
  }
  return 0;
}
