#include <bits/stdc++.h>
using namespace std;
const int N = (1 << 18) + 5;
int n, m, t, q;
long long a[N], tree[N << 2], lazy[30];
void build(int x, int l, int r) {
  if (l == r)
    tree[x] = a[l];
  else {
    int mid = (l + r) / 2;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
    tree[x] = tree[x << 1] + tree[x << 1 | 1];
  }
}
void update(int x, int L, int R, int id, int val, int dep) {
  if (L == R && L == id)
    tree[x] = val;
  else {
    int mid = (L + R) / 2;
    if (lazy[dep]) {
      if (id <= mid)
        update(x << 1 | 1, L, mid, id, val, dep - 1);
      else
        update(x << 1, mid + 1, R, id, val, dep - 1);
    } else {
      if (id <= mid)
        update(x << 1, L, mid, id, val, dep - 1);
      else
        update(x << 1 | 1, mid + 1, R, id, val, dep - 1);
    }
    tree[x] = tree[x << 1] + tree[x << 1 | 1];
  }
}
long long query(int x, int L, int R, int l, int r, int dep) {
  if (l <= L && R <= r)
    return tree[x];
  else {
    long long ans = 0;
    int mid = (L + R) / 2;
    if (lazy[dep]) {
      if (mid >= l) ans += query(x << 1 | 1, L, mid, l, r, dep - 1);
      if (mid < r) ans += query(x << 1, mid + 1, R, l, r, dep - 1);
    } else {
      if (mid >= l) ans += query(x << 1, L, mid, l, r, dep - 1);
      if (mid < r) ans += query(x << 1 | 1, mid + 1, R, l, r, dep - 1);
    }
    tree[x] = tree[x << 1] + tree[x << 1 | 1];
    return ans;
  }
}
int main() {
  scanf("%d%d", &n, &q);
  int up = 1 << n;
  for (int i = (1); i <= (up); i++) scanf("%lld", &a[i]);
  build(1, 1, up);
  while (q--) {
    int op, x, y;
    scanf("%d%d", &op, &x);
    if (op == 1) {
      scanf("%d", &y);
      update(1, 1, up, x, y, n);
    } else if (op == 2) {
      for (int i = (0); i <= (x); i++) lazy[i] ^= 1;
    } else if (op == 3)
      lazy[x + 1] ^= 1;
    else {
      scanf("%d", &y);
      printf("%lld\n", query(1, 1, up, x, y, n));
    }
  }
  return 0;
}
