#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
const long long p[8] =
    {42,        1764,         74088,          3111696,
     130691232, 5489031744ll, 230539333248ll, 9682651996416ll},
                INF = 1e16;
struct node {
  pair<long long, int> min;
  long long add, val;
  void cover(long long val) {
    this->val = val;
    add = 0;
    min.first = *lower_bound(p, p + 8, val) - val;
  }
  void plus(long long val) {
    if (this->val)
      cover(this->val + val);
    else {
      add += val;
      min.first -= val;
    }
  }
} tree[N * 4];
void build(int id, int l, int r) {
  if (l == r) {
    cin >> tree[id].val;
    tree[id].min =
        make_pair(*lower_bound(p, p + 8, tree[id].val) - tree[id].val, l);
  } else {
    int mid = (l + r) / 2;
    build(id * 2, l, mid);
    build(id * 2 + 1, mid + 1, r);
    tree[id].min = min(tree[id * 2].min, tree[id * 2 + 1].min);
  }
}
inline void pushdown(int id) {
  if (tree[id].val) {
    tree[id * 2].cover(tree[id].val);
    tree[id * 2 + 1].cover(tree[id].val);
    tree[id].val = 0;
  }
  if (tree[id].add) {
    tree[id * 2].plus(tree[id].add);
    tree[id * 2 + 1].plus(tree[id].add);
    tree[id].add = 0;
  }
}
void add(int id, int l, int r, int L, int R, int val) {
  if (L <= l && R >= r)
    tree[id].plus(val);
  else {
    pushdown(id);
    int mid = (l + r) / 2;
    if (L <= mid) add(id * 2, l, mid, L, R, val);
    if (R > mid) add(id * 2 + 1, mid + 1, r, L, R, val);
    tree[id].min = min(tree[id * 2].min, tree[id * 2 + 1].min);
  }
}
pair<long long, int> query(int id, int l, int r, int L, int R) {
  if (L <= l && R >= r) return tree[id].min;
  pushdown(id);
  int mid = (l + r) / 2;
  if (R <= mid) return query(id * 2, l, mid, L, R);
  if (L > mid) return query(id * 2 + 1, mid + 1, r, L, R);
  return min(query(id * 2, l, mid, L, R), query(id * 2 + 1, mid + 1, r, L, R));
}
void reset(int id, int l, int r, int x) {
  if (l == r)
    tree[id].min.first = *lower_bound(p, p + 8, tree[id].val) - tree[id].val;
  else {
    pushdown(id);
    int mid = (l + r) / 2;
    if (x <= mid)
      reset(id * 2, l, mid, x);
    else
      reset(id * 2 + 1, mid + 1, r, x);
    tree[id].min = min(tree[id * 2].min, tree[id * 2 + 1].min);
  }
}
void cover(int id, int l, int r, int L, int R, int val) {
  if (L <= l && R >= r)
    tree[id].cover(val);
  else {
    pushdown(id);
    int mid = (l + r) / 2;
    if (L <= mid) cover(id * 2, l, mid, L, R, val);
    if (R > mid) cover(id * 2 + 1, mid + 1, r, L, R, val);
    tree[id].min = min(tree[id * 2].min, tree[id * 2 + 1].min);
  }
}
long long query(int id, int l, int r, int x) {
  if (l == r) return tree[id].val;
  pushdown(id);
  int mid = (l + r) / 2;
  if (x <= mid) return query(id * 2, l, mid, x);
  return query(id * 2 + 1, mid + 1, r, x);
}
int main() {
  ios::sync_with_stdio(false);
  int n, q;
  cin >> n >> q;
  build(1, 1, n);
  while (q--) {
    int opt, a, b, x;
    pair<long long, int> ret;
    cin >> opt;
    switch (opt) {
      case 1:
        cin >> x;
        cout << query(1, 1, n, x) << endl;
        break;
      case 2:
        cin >> a >> b >> x;
        cover(1, 1, n, a, b, x);
        break;
      case 3:
        cin >> a >> b >> x;
        do {
          add(1, 1, n, a, b, x);
          ret = query(1, 1, n, a, b);
          while (ret.first < 0) {
            reset(1, 1, n, ret.second);
            ret = query(1, 1, n, a, b);
          }
        } while (ret.first == 0);
        break;
    }
  }
  return 0;
}
