#include <bits/stdc++.h>
using namespace std;
int n, q, x;
int stsize, bstart;
long long segtree[300300 * 4];
void upd(int ind, long long v) {
  ind = bstart + ind;
  while (ind >= 0) {
    if (ind >= bstart)
      segtree[ind] = v;
    else
      segtree[ind] = segtree[ind * 2 + 1] + segtree[ind * 2 + 2];
    if (ind == 0) break;
    ind = (ind - 1) / 2;
  }
}
long long queryutil(int c, int cmin, int cmax, int minb, int maxb) {
  if (cmin >= minb && cmax <= maxb) return segtree[c];
  if (cmin > maxb || cmax < minb) return 0;
  return queryutil(c * 2 + 1, cmin, (cmin + cmax) / 2, minb, maxb) +
         queryutil(c * 2 + 2, 1 + (cmin + cmax) / 2, cmax, minb, maxb);
}
long long query(int c, int cmin, int cmax, int minb, int maxb) {
  int l = 1, k = 0;
  while (l < (cmax - cmin + 1)) l *= 2, k++;
  if (cmin >= minb && cmax <= maxb)
    return queryutil(0, 0, bstart, cmin ^ (x & (~((1 << k) - 1))),
                     cmax ^ (x & (~((1 << k) - 1))));
  if (cmin > maxb || cmax < minb) return 0;
  return query(c * 2 + 1, cmin, (cmin + cmax) / 2, minb, maxb) +
         query(c * 2 + 2, 1 + (cmin + cmax) / 2, cmax, minb, maxb);
}
int main() {
  scanf(" %d%d", &n, &q);
  x = 0;
  n = 1 << n;
  bstart = 1;
  while (bstart < n) bstart *= 2;
  stsize = bstart * 2 - 1;
  bstart--;
  memset(segtree, 0, sizeof(segtree));
  for (int i = 0; i < n; i++) {
    long long v;
    scanf("%lld", &v);
    upd(i, v);
  }
  for (int i = 0; i < q; i++) {
    int type;
    scanf("%d", &type);
    if (type == 1) {
      int ind;
      long long newv;
      scanf(" %d%lld", &ind, &newv);
      ind--;
      upd(ind ^ x, newv);
    } else if (type == 2) {
      int k;
      scanf(" %d", &k);
      x = x ^ ((1 << k) - 1);
    } else if (type == 3) {
      int k;
      scanf(" %d", &k);
      x = x ^ (1 << k);
    } else {
      int l, r;
      scanf(" %d%d", &l, &r);
      printf("%lld\n", query(0, 0, bstart, l - 1, r - 1));
    }
  }
}
