#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(i, j) (i < j ? i : j)
#define max(i, j) (i > j ? i : j)
const int maxn = 5e6 + 10;
const int maxm = 1e5 + 10;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(ll x)
{
    if (x == 0)
    {
        putchar('0');
        return;
    }
    char F[200];
    ll tmp = x > 0 ? x : -x;
    if (x < 0)
        putchar('-');
    ll cnt = 0;
    while (tmp > 0)
    {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0)
        putchar(F[--cnt]);
}
vector<int> savedep[30];
int getdep[maxn];
struct TREE
{
    int lid[maxn];
    int rid[maxn];
    int tag[maxn];
    ll val[maxn];
    void init()
    {
        memset(lid, 0, sizeof(lid));
        memset(rid, 0, sizeof(rid));
        memset(tag, 0, sizeof(tag));
        memset(val, 0, sizeof(val));
    }
    void build(int nowid, int l, int r)
    {
        int dep = getdep[r - l + 1];
        savedep[dep].push_back(nowid);
        if (l == r)
        {
            // scanf("%lld", &val[nowid]);
            val[nowid] = read();
            return;
        }
        int mid = (l + r) / 2;
        lid[nowid] = nowid * 2;
        rid[nowid] = nowid * 2 + 1;
        build(lid[nowid], l, mid);
        build(rid[nowid], mid + 1, r);
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }

    inline void pushdown(int nowid)
    {
        if (tag[nowid])
        {
            tag[nowid] = 0;
            tag[lid[nowid]]++;
            tag[lid[nowid]] %= 2;
            tag[rid[nowid]]++;
            tag[rid[nowid]] %= 2;
            swap(lid[nowid], rid[nowid]);
        }
    }

    ll query(int nowid, int l, int r, int ql, int qr)
    {
        if (ql <= l && r <= qr)
        {
            return val[nowid];
        }
        pushdown(nowid);
        int mid = (l + r) / 2;
        ll res = 0;
        if (ql <= mid)
        {
            res += query(lid[nowid], l, mid, ql, qr);
        }
        if (mid < qr)
        {
            res += query(rid[nowid], mid + 1, r, ql, qr);
        }
        return res;
    }

    void update(int nowid, int l, int r, int pos, ll v)
    {
        if (l == r)
        {
            val[nowid] = v;
            return;
        }
        pushdown(nowid);
        int mid = (l + r) / 2;
        if (pos <= mid)
        {
            update(lid[nowid], l, mid, pos, v);
        }
        else
        {
            update(rid[nowid], mid + 1, r, pos, v);
        }
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }
} tr;

int main()
{
    // freopen("in.txt", "r", stdin);
    // tr.init();
    int n, q;
    n = read();
    q = read();
    for (int i = 0; i <= n; i++)
    {
        getdep[(1 << i)] = i;
    }
    int R = 1 << n;
    tr.build(1, 1, R);
        while (q--)
        {
            int t;
            t = read();
            // scanf("%d", &t);
            if (t == 1)
            {
                ll v;
                int p;
                // scanf("%d %lld", &p, &v);
                p = read();
                v = read();
                tr.update(1, 1, R, p, v);
            }
            if (t == 2)
            {
                int k;
                k = read();
                // scanf("%d", &k);
                for (int id : savedep[k])
                {
                    tr.tag[id]++;
                    tr.tag[id] %= 2;
                }
            }
            if (t == 3)
            {
                int k;
                // scanf("%d", &k);
                k = read();
                k++;
                for (int id : savedep[k])
                {
                    swap(tr.lid[id], tr.rid[id]);
                }
            }
            if (t == 4)
            {
                int l, r;
                l = read();
                r = read();
                // scanf("%d %d", &l, &r);
                // printf("%lld\n", tr.query(1, 1, R, l, r));
                ll tempans = tr.query(1, 1, R, l, r);
                write(tempans);
                puts("");
            }
        }
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(i, j) (i < j ? i : j)
#define max(i, j) (i > j ? i : j)
const int maxn = 3e6 + 10;
const int maxm = 1e5 + 10;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(ll x)
{
    if (x == 0)
    {
        putchar('0');
        return;
    }
    char F[200];
    ll tmp = x > 0 ? x : -x;
    if (x < 0)
        putchar('-');
    ll cnt = 0;
    while (tmp > 0)
    {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0)
        putchar(F[--cnt]);
}

int getdep[maxn];
struct TREE
{
    int lid[maxn];
    int rid[maxn];
    ll val[maxn];
//递归旋转
    int allneed[30];
    int allnow[maxn];
    //单点旋转，标记所需要的旋转次数和已经执行的旋转次数
    int changnow[maxn];
    int needchang[30];
    //递归给某一个节点
    int tag[maxn];

    void init()
    {
        memset(lid, 0, sizeof(lid));
        memset(rid, 0, sizeof(rid));
        memset(val, 0, sizeof(val));
        memset(allneed, 0, sizeof(allneed));
        memset(allnow, 0, sizeof(allnow));
        memset(changnow, 0, sizeof(changnow));
        memset(needchang, 0, sizeof(needchang));
        memset(tag, 0, sizeof(tag));
    }
    void build(int nowid, int l, int r)
    {
        if (l == r)
        {
            scanf("%lld", &val[nowid]);
            return;
        }
        int mid = (l + r) / 2;
        lid[nowid] = nowid * 2;
        rid[nowid] = nowid * 2 + 1;
        build(lid[nowid], l, mid);
        build(rid[nowid], mid + 1, r);
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }

    inline void pushdown(int nowid, int l, int r)
    {
        int dep = getdep[r - l + 1];
        //处理单点旋转
        if( (needchang[dep] - changnow[nowid]) % 2){
            changnow[nowid] = needchang[dep];
            swap(lid[nowid], rid[nowid]);
        }
        if(tag[nowid]){
            swap(lid[nowid], rid[nowid]);
            tag[nowid] = 0;
            tag[lid[nowid]]++;
            tag[lid[nowid]] %= 2;
            tag[rid[nowid]]++;
            tag[rid[nowid]] %= 2;
        }
        //处理递归旋转
        if ( (allneed[dep] - allnow[nowid]) % 2)
        {
            allnow[nowid] = allneed[dep];
            tag[lid[nowid]]++;
            tag[rid[nowid]]++;
            tag[lid[nowid]] %= 2;
            tag[rid[nowid]] %= 2;
            swap(lid[nowid], rid[nowid]);
        }
    }

    ll query(int nowid, int l, int r, int ql, int qr)
    {
        if (ql <= l && r <= qr)
        {
            return val[nowid];
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        ll res = 0;
        if (ql <= mid)
        {
            res += query(lid[nowid], l, mid, ql, qr);
        }
        if (mid < qr)
        {
            res += query(rid[nowid], mid + 1, r, ql, qr);
        }
        return res;
    }

    void update(int nowid, int l, int r, int pos, ll v)
    {
        if (l == r)
        {
            val[nowid] = v;
            return;
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        if (pos <= mid)
        {
            update(lid[nowid], l, mid, pos, v);
        }
        else
        {
            update(rid[nowid], mid + 1, r, pos, v);
        }
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }
} tr;

int main()
{
    int n, q;
    scanf("%d %d", &n, &q);
    for (int i = 0; i <= n; i++)
    {
        getdep[(1 << i)] = i;
    }

    int R = 1 << n;
    tr.build(1, 1, R);
        while (q--)
        {
            int t;
            // t = read();
            scanf("%d", &t);
            if (t == 1)
            {
                ll v;
                int p;
                scanf("%d %lld", &p, &v);
                tr.update(1, 1, R, p, v);
            }
            if (t == 2)
            {
                int k;
                // k = read();
                scanf("%d", &k);
                tr.allneed[k]++;
            }
            if (t == 3)
            {
                int k;
                scanf("%d", &k);
                k++;
                //这一层的单点旋转次数+1
                tr.needchang[k]++;
            }
            if (t == 4)
            {
                int l, r;
                scanf("%d %d", &l, &r);
                ll tempans = tr.query(1, 1, R, l, r);
                printf("%lld\n", tempans);
            }
        }
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(i, j) (i < j ? i : j)
#define max(i, j) (i > j ? i : j)
const int maxn = 3e6 + 10;
const int maxm = 1e5 + 10;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(ll x)
{
    if (x == 0)
    {
        putchar('0');
        return;
    }
    char F[200];
    ll tmp = x > 0 ? x : -x;
    if (x < 0)
        putchar('-');
    ll cnt = 0;
    while (tmp > 0)
    {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0)
        putchar(F[--cnt]);
}

int getdep[maxn];
struct TREE
{
    int lid[maxn];
    int rid[maxn];
    ll val[maxn];
//递归旋转
    int allneed[30];
    int allnow[maxn];
    //单点旋转，标记所需要的旋转次数和已经执行的旋转次数
    int changnow[maxn];
    int needchang[30];
    //递归给某一个节点
    int tag[maxn];

    void init()
    {
        memset(lid, 0, sizeof(lid));
        memset(rid, 0, sizeof(rid));
        memset(val, 0, sizeof(val));
        memset(allneed, 0, sizeof(allneed));
        memset(allnow, 0, sizeof(allnow));
        memset(changnow, 0, sizeof(changnow));
        memset(needchang, 0, sizeof(needchang));
    }
    void build(int nowid, int l, int r)
    {
        if (l == r)
        {
            val[nowid] = read();
            return;
        }
        int mid = (l + r) / 2;
        lid[nowid] = nowid * 2;
        rid[nowid] = nowid * 2 + 1;
        build(lid[nowid], l, mid);
        build(rid[nowid], mid + 1, r);
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }

    inline void pushdown(int nowid, int l, int r)
    {
        int dep = getdep[r - l + 1];
        //处理单点旋转
        if( (needchang[dep] - changnow[nowid]) % 2){
            changnow[nowid] = needchang[dep];
            swap(lid[nowid], rid[nowid]);
        }
        if(tag[nowid]){
            swap(lid[nowid], rid[nowid]);
            tag[nowid] = 0;
            tag[lid[nowid]]++;
            tag[rid[nowid]]++;
        }
        //处理递归旋转
        if ( (allneed[dep] - allnow[nowid]) %2)
        {
            allnow[nowid] = allneed[dep];
            tag[lid[nowid]]++;
            tag[rid[nowid]]++;
            tag[lid[nowid]] %= 2;
            tag[rid[nowid]] %= 2;
            swap(lid[nowid], rid[nowid]);
        }
    }

    ll query(int nowid, int l, int r, int ql, int qr)
    {
        if (ql <= l && r <= qr)
        {
            return val[nowid];
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        ll res = 0;
        if (ql <= mid)
        {
            res += query(lid[nowid], l, mid, ql, qr);
        }
        if (mid < qr)
        {
            res += query(rid[nowid], mid + 1, r, ql, qr);
        }
        return res;
    }

    void update(int nowid, int l, int r, int pos, ll v)
    {
        if (l == r)
        {
            val[nowid] = v;
            return;
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        if (pos <= mid)
        {
            update(lid[nowid], l, mid, pos, v);
        }
        else
        {
            update(rid[nowid], mid + 1, r, pos, v);
        }
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }
} tr;

int main()
{
    // freopen("in.txt", "r", stdin);
    int n, q;
    n = read();
    q = read();
    for (int i = 0; i <= n; i++)
    {
        getdep[(1 << i)] = i;
    }
    int R = 1 << n;
    tr.build(1, 1, R);
        while (q--)
        {
            int t;
            t = read();
            if (t == 1)
            {
                ll v;
                int p;
                p = read();
                v = read();
                tr.update(1, 1, R, p, v);
            }
            if (t == 2)
            {
                int k;
                k = read();
                //递归旋转
                tr.allneed[k]++;
            }
            if (t == 3)
            {
                int k;
                k = read();
                k++;
                //这一层的单点旋转次数+1
                tr.needchang[k]++;
            }
            if (t == 4)
            {
                int l, r;
                l = read();
                r = read();
                ll tempans = tr.query(1, 1, R, l, r);
                write(tempans);
                puts("");
            }
        }
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(i, j) (i < j ? i : j)
#define max(i, j) (i > j ? i : j)
const int maxn = 3e6 + 10;
const int maxm = 1e5 + 10;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(ll x)
{
    if (x == 0)
    {
        putchar('0');
        return;
    }
    char F[200];
    ll tmp = x > 0 ? x : -x;
    if (x < 0)
        putchar('-');
    ll cnt = 0;
    while (tmp > 0)
    {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0)
        putchar(F[--cnt]);
}

int getdep[maxn];
struct TREE
{
    int lid[maxn];
    int rid[maxn];
    ll val[maxn];
//递归旋转
    int allneed[30];
    int allnow[maxn];
    //单点旋转，标记所需要的旋转次数和已经执行的旋转次数
    int changnow[maxn];
    int needchang[30];

    void init()
    {
        memset(lid, 0, sizeof(lid));
        memset(rid, 0, sizeof(rid));
        memset(val, 0, sizeof(val));
        memset(allneed, 0, sizeof(allneed));
        memset(allnow, 0, sizeof(allnow));
        memset(changnow, 0, sizeof(changnow));
        memset(needchang, 0, sizeof(needchang));
    }
    void build(int nowid, int l, int r)
    {
        if (l == r)
        {
            val[nowid] = read();
            return;
        }
        int mid = (l + r) / 2;
        lid[nowid] = nowid * 2;
        rid[nowid] = nowid * 2 + 1;
        build(lid[nowid], l, mid);
        build(rid[nowid], mid + 1, r);
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }

    inline void pushdown(int nowid, int l, int r)
    {
        int dep = getdep[r - l + 1];
        //处理单点旋转
        if( (needchang[dep] - changnow[nowid]) % 2){
            changnow[nowid] = needchang[dep];
            swap(lid[nowid], rid[nowid]);
        }
        //处理递归旋转
        if ( (allneed[dep] - allnow[nowid]) %2)
        {
            allnow[nowid] = allneed[dep];
            allneed[dep - 1]++;
            swap(lid[nowid], rid[nowid]);
        }
    }

    ll query(int nowid, int l, int r, int ql, int qr)
    {
        if (ql <= l && r <= qr)
        {
            return val[nowid];
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        ll res = 0;
        if (ql <= mid)
        {
            res += query(lid[nowid], l, mid, ql, qr);
        }
        if (mid < qr)
        {
            res += query(rid[nowid], mid + 1, r, ql, qr);
        }
        return res;
    }

    void update(int nowid, int l, int r, int pos, ll v)
    {
        if (l == r)
        {
            val[nowid] = v;
            return;
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        if (pos <= mid)
        {
            update(lid[nowid], l, mid, pos, v);
        }
        else
        {
            update(rid[nowid], mid + 1, r, pos, v);
        }
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }
} tr;

int main()
{
    // freopen("in.txt", "r", stdin);
    int n, q;
    n = read();
    q = read();
    for (int i = 0; i <= n; i++)
    {
        getdep[(1 << i)] = i;
    }
    int R = 1 << n;
    tr.build(1, 1, R);
        while (q--)
        {
            int t;
            t = read();
            if (t == 1)
            {
                ll v;
                int p;
                p = read();
                v = read();
                tr.update(1, 1, R, p, v);
            }
            if (t == 2)
            {
                int k;
                k = read();
                //递归旋转
                tr.allneed[k]++;
            }
            if (t == 3)
            {
                int k;
                k = read();
                k++;
                //这一层的单点旋转次数+1
                tr.needchang[k]++;
            }
            if (t == 4)
            {
                int l, r;
                l = read();
                r = read();
                ll tempans = tr.query(1, 1, R, l, r);
                write(tempans);
                puts("");
            }
        }
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(i, j) (i < j ? i : j)
#define max(i, j) (i > j ? i : j)
const int maxn = 3e6 + 10;
const int maxm = 1e5 + 10;

vector<int> savedep[maxn];

struct TREE{
    int lid[maxn];
    int rid[maxn];
    int tag[maxn];
    ll val[maxn];

    void build(int nowid, int l, int r){
        int dep = log((r - l + 1)) / log(2);
        savedep[dep].push_back(nowid);
        if(l==r){
            scanf("%lld", &val[nowid]);
            return;
        }
        int mid = (l + r) / 2;
        lid[nowid] = nowid * 2;
        rid[nowid] = nowid * 2 + 1;
        build(lid[nowid], l, mid);
        build(rid[nowid], mid + 1, r);
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }

    inline void pushdown(int nowid){
        if(tag[nowid]){
            tag[nowid] = 0;
            tag[lid[nowid]]++;
            tag[lid[nowid]] %= 2;
            tag[rid[nowid]]++;
            tag[rid[nowid]] %= 2;
            swap(lid[nowid], rid[nowid]);
        }
    }

    ll query(int nowid, int l, int r, int ql, int qr){
        if(ql <= l && r <= qr){
            return val[nowid];
        }
        pushdown(nowid);
        int mid = (l + r) / 2;
        ll res = 0;
        if(ql<=mid){
            res += query(lid[nowid], l, mid, ql, qr);
        }
        if(mid <qr){
            res += query(rid[nowid], mid + 1, r, ql, qr);
        }
        return res;
    }

    void update(int nowid, int l, int r, int pos, ll v){
        if(l==r){
            val[nowid] = v;
            return;
        }
        pushdown(nowid);
        int mid = (l + r) / 2;
        if(pos<=mid){
            update(lid[nowid], l, mid, pos, v);
        }
        else{
            update(rid[nowid], mid + 1, r, pos, v);
        }
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }
} tr;

int main(){
    // freopen("in.txt", "r", stdin);
    int n, q;
    cin >> n >> q;
    tr.build(1, 1, (1 << n));

    while(q--){
        int t;
        cin >> t;
        if(t==1){
            ll v;
            int p;
            cin >> p >> v;
            tr.update(1, 1, (1 << n), p, v);
        }
        if(t==2){
            int k;
            cin >> k;
            for(int id:savedep[k]){
                tr.tag[id]++;
                tr.tag[id] %= 2;
            }
        }
        if(t==3){
            int k;
            cin >> k;
            k++;
            for(int id:savedep[k]){
                swap(tr.lid[id], tr.rid[id]);
            }
        }
        if(t==4){
            int l, r;
            cin >> l >> r;
            cout << tr.query(1, 1, (1 << n), l, r) << endl;
        }
    }
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(i, j) (i < j ? i : j)
#define max(i, j) (i > j ? i : j)
const int maxn = 3e6 + 10;
const int maxm = 1e5 + 10;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(ll x)
{
    if (x == 0)
    {
        putchar('0');
        return;
    }
    char F[200];
    ll tmp = x > 0 ? x : -x;
    if (x < 0)
        putchar('-');
    ll cnt = 0;
    while (tmp > 0)
    {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0)
        putchar(F[--cnt]);
}

int getdep[maxn];
struct TREE
{
    int lid[maxn];
    int rid[maxn];
    ll val[maxn];
//递归旋转
    int allneed[30];
    int allnow[maxn];
    //单点旋转，标记所需要的旋转次数和已经执行的旋转次数
    int changnow[maxn];
    int needchang[30];
    //递归给某一个节点
    int tag[maxn];

    void init()
    {
        memset(lid, 0, sizeof(lid));
        memset(rid, 0, sizeof(rid));
        memset(val, 0, sizeof(val));
        memset(allneed, 0, sizeof(allneed));
        memset(allnow, 0, sizeof(allnow));
        memset(changnow, 0, sizeof(changnow));
        memset(needchang, 0, sizeof(needchang));
    }
    void build(int nowid, int l, int r)
    {
        if (l == r)
        {
            val[nowid] = read();
            return;
        }
        int mid = (l + r) / 2;
        lid[nowid] = nowid * 2;
        rid[nowid] = nowid * 2 + 1;
        build(lid[nowid], l, mid);
        build(rid[nowid], mid + 1, r);
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }

    inline void pushdown(int nowid, int l, int r)
    {
        int dep = getdep[r - l + 1];
        //处理单点旋转
        if( (needchang[dep] - changnow[nowid]) % 2){
            changnow[nowid] = needchang[dep];
            swap(lid[nowid], rid[nowid]);
        }
        if(tag[nowid]){
            swap(lid[nowid], rid[nowid]);
            tag[nowid] = 0;
            tag[lid[nowid]]++;
            tag[rid[nowid]]++;
        }
        //处理递归旋转
        if ( (allneed[dep] - allnow[nowid]) %2)
        {
            allnow[nowid] = allneed[dep];
            tag[lid[nowid]]++;
            tag[rid[nowid]]++;
            tag[lid[nowid]] %= 2;
            tag[rid[nowid]] %= 2;
            swap(lid[nowid], rid[nowid]);
        }
    }

    ll query(int nowid, int l, int r, int ql, int qr)
    {
        if (ql <= l && r <= qr)
        {
            return val[nowid];
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        ll res = 0;
        if (ql <= mid)
        {
            res += query(lid[nowid], l, mid, ql, qr);
        }
        if (mid < qr)
        {
            res += query(rid[nowid], mid + 1, r, ql, qr);
        }
        return res;
    }

    void update(int nowid, int l, int r, int pos, ll v)
    {
        if (l == r)
        {
            val[nowid] = v;
            return;
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        if (pos <= mid)
        {
            update(lid[nowid], l, mid, pos, v);
        }
        else
        {
            update(rid[nowid], mid + 1, r, pos, v);
        }
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }
} tr;

int main()
{
    int n, q;
    scanf("%d %d", &n, &q);
    for (int i = 0; i <= n; i++)
    {
        getdep[(1 << i)] = i;
    }

    int R = 1 << n;
    tr.build(1, 1, R);
        while (q--)
        {
            int t;
            // t = read();
            scanf("%d", &t);
            if (t == 1)
            {
                ll v;
                int p;
                scanf("%d %lld", &p, &v);
                tr.update(1, 1, R, p, v);
            }
            if (t == 2)
            {
                int k;
                // k = read();
                scanf("%d", &k);
                tr.allneed[k]++;
            }
            if (t == 3)
            {
                int k;
                scanf("%d", &k);
                k++;
                //这一层的单点旋转次数+1
                tr.needchang[k]++;
            }
            if (t == 4)
            {
                int l, r;
                scanf("%d %d", &l, &r);
                ll tempans = tr.query(1, 1, R, l, r);
                printf("%lld\n", tempans);
            }
        }
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define min(i, j) (i < j ? i : j)
#define max(i, j) (i > j ? i : j)
const int maxn = 3e6 + 10;
const int maxm = 1e5 + 10;
inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
inline void write(ll x)
{
    if (x == 0)
    {
        putchar('0');
        return;
    }
    char F[200];
    ll tmp = x > 0 ? x : -x;
    if (x < 0)
        putchar('-');
    ll cnt = 0;
    while (tmp > 0)
    {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0)
        putchar(F[--cnt]);
}

int getdep[maxn];
struct TREE
{
    int lid[maxn];
    int rid[maxn];
    ll val[maxn];
//递归旋转
    int allneed[30];
    int allnow[maxn];
    //单点旋转，标记所需要的旋转次数和已经执行的旋转次数
    int changnow[maxn];
    int needchang[30];
    //递归给某一个节点
    int tag[maxn];

    void init()
    {
        memset(lid, 0, sizeof(lid));
        memset(rid, 0, sizeof(rid));
        memset(val, 0, sizeof(val));
        memset(allneed, 0, sizeof(allneed));
        memset(allnow, 0, sizeof(allnow));
        memset(changnow, 0, sizeof(changnow));
        memset(needchang, 0, sizeof(needchang));
    }
    void build(int nowid, int l, int r)
    {
        if (l == r)
        {
            val[nowid] = read();
            return;
        }
        int mid = (l + r) / 2;
        lid[nowid] = nowid * 2;
        rid[nowid] = nowid * 2 + 1;
        build(lid[nowid], l, mid);
        build(rid[nowid], mid + 1, r);
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }

    inline void pushdown(int nowid, int l, int r)
    {
        int dep = getdep[r - l + 1];
        //处理单点旋转
        if( (needchang[dep] - changnow[nowid]) % 2){
            changnow[nowid] = needchang[dep];
            swap(lid[nowid], rid[nowid]);
        }
        if(tag[nowid]){
            swap(lid[nowid], rid[nowid]);
            tag[nowid] = 0;
            tag[lid[nowid]]++;
            tag[rid[nowid]]++;
        }
        //处理递归旋转
        if ( (allneed[dep] - allnow[nowid]) %2)
        {
            allnow[nowid] = allneed[dep];
            tag[lid[nowid]]++;
            tag[rid[nowid]]++;
            tag[lid[nowid]] %= 2;
            tag[rid[nowid]] %= 2;
            swap(lid[nowid], rid[nowid]);
        }
    }

    ll query(int nowid, int l, int r, int ql, int qr)
    {
        if (ql <= l && r <= qr)
        {
            return val[nowid];
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        ll res = 0;
        if (ql <= mid)
        {
            res += query(lid[nowid], l, mid, ql, qr);
        }
        if (mid < qr)
        {
            res += query(rid[nowid], mid + 1, r, ql, qr);
        }
        return res;
    }

    void update(int nowid, int l, int r, int pos, ll v)
    {
        if (l == r)
        {
            val[nowid] = v;
            return;
        }
        pushdown(nowid, l, r);
        int mid = (l + r) / 2;
        if (pos <= mid)
        {
            update(lid[nowid], l, mid, pos, v);
        }
        else
        {
            update(rid[nowid], mid + 1, r, pos, v);
        }
        val[nowid] = val[lid[nowid]] + val[rid[nowid]];
    }
} tr;

int main()
{
    freopen("in.txt", "r", stdin);
    int n, q;
    n = read();
    q = read();
    for (int i = 0; i <= n; i++)
    {
        getdep[(1 << i)] = i;
    }
    int R = 1 << n;
    tr.build(1, 1, R);
        while (q--)
        {
            int t;
            t = read();
            if (t == 1)
            {
                ll v;
                int p;
                p = read();
                v = read();
                tr.update(1, 1, R, p, v);
            }
            if (t == 2)
            {
                int k;
                k = read();
                //递归旋转
                tr.allneed[k]++;
            }
            if (t == 3)
            {
                int k;
                k = read();
                k++;
                //这一层的单点旋转次数+1
                tr.needchang[k]++;
            }
            if (t == 4)
            {
                int l, r;
                l = read();
                r = read();
                ll tempans = tr.query(1, 1, R, l, r);
                write(tempans);
                puts("");
            }
        }
}


//orz Gold_7
//orz SqwrIwy
//orz yzh1505
//orz yzh2019
//orz new
//orz hejinfan
//orz chenkuowen
//#pragma comment(linker,?STACK:1677721600?
//#pragma GCC optimize("O2")
//#pragma G++ optimize("O2")
//#pragma GCC optimize("O3")
//#pragma G++ optimize("O3")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 ll;
typedef unsigned int uint;
typedef unsigned long long ull;
//typedef double db;
typedef long double ld;
typedef pair<int,int> PII;
typedef pair<ll,int> Pli;
typedef pair<ll,ll> Pll;
typedef vector<int> VI;
typedef vector<PII> VII;
//typedef pair<ll,ll>P;
#define fi first
#define se second
#define MP make_pair
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
#define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
#define REP(i,n) for(int i=0;i<n;++i)
#define lowbit(x) x&(-x)
#define Rand (rand()*(1<<16)+rand())
#define id(x) ((x)<=B?(x):m-n/(x)+1)
#define fors(i) for(auto i:e[x]) if(i!=p)
//#define ls p<<1
//#define rs p<<1|1

#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Flush FastIO::Fflush()

const int N=500010;
const int M=222222;
const int MOD=1e9+7;
const int intINF=int(1e9);
const ll llINF=ll(2e18);
const uint uintINF=~0U;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
const long double pi=acos(-1.0L);

int read()
{
   int v=0,f=1;
   char c=getchar();
   while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
   while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
   return v*f;
}

ll readll()
{
   ll v=0,f=1;
   char c=getchar();
   while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
   while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
   return v*f;
}

/*
void pr128(__int128 x)
{
    if(x<0) putchar('-'),x=-x;
    if(x<10) return putchar('0'+x),void();
    pr128(x/10),putchar('0'+(x%10));
}*/

/*namespace FastIO
{
    const int SIZE = 1 << 16;
    char buf[SIZE], obuf[SIZE], str[60];
    int bi = SIZE, bn = SIZE, opt;
    double D[] = {0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001, 0.0000000001};
    int read(char *s) {
        while (bn) {
            for (; bi < bn && buf[bi] <= ' '; bi++);
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        int sn = 0;
        while (bn) {
            for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        s[sn] = 0;
        return sn;
    }
    bool read(int& x) {
        int n = read(str), bf = 0;
        if (!n) return 0;
        int i = 0; if (str[i] == '-') bf = 1, i++; else if (str[i] == '+') i++;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf) x = -x;
        return 1;
    }
    bool read(long long& x) {
        int n = read(str), bf;
        if (!n) return 0;
        int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf < 0) x = -x;
        return 1;
    }
    void write(int x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            if (x < 0) obuf[opt++] = '-', x = -x;
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(long long x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            if (x < 0) obuf[opt++] = '-', x = -x;
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(unsigned long long x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(char x) {
        obuf[opt++] = x;
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void Fflush() { if (opt) fwrite(obuf, 1, opt, stdout); opt = 0;}
};

//int x=read();   ->int x; FI(x);*/

/*auto random_address = [] { char *p = new char; delete p; return uint64_t(p); };
const uint64_t SEED = chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1);
mt19937_64 rng(SEED);

ull SX=335634763,SY=873658265,SZ=192849106,SW=746126501;

inline ull xorshift128()
{
    ull t=SX^(SX<<11);
    SX=SY;
    SY=SZ;
    SZ=SW;
    return SW=SW^(SW>>19)^t^(t>>8);
}*/

void predo()
{
}

ll t[N<<2],a[N];
int c[20],n,q,tot;

void init()
{
    n=read(),q=read();
    tot=1<<n;
    rep(i,1,tot) a[i]=readll();
}

void pushup(int p)
{
    t[p]=t[p<<1]+t[p<<1|1];
}

void build(int l,int r,int p)
{
    if(l==r)
    {
        t[p]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,p<<1);
    build(mid+1,r,p<<1|1);
    pushup(p);
}

void update(int l,int r,int x,ll y,int p,int d)
{
    if(l==r)
    {
        t[p]=y;
        return;
    }
    int mid=(l+r)>>1;
    int ls=p<<1,rs=ls+1;
    if(c[d]) swap(ls,rs);
    if(x<=mid) update(l,mid,x,y,ls,d-1);
     else update(mid+1,r,x,y,rs,d-1);
    pushup(p);
}

ll query(int l,int r,int x,int y,int p,int d)
{
    if(x<=l&&r<=y) return t[p];
    int mid=(l+r)>>1;
    int ls=p<<1,rs=ls+1;
    if(c[d]) swap(ls,rs);
    ll res=0;
    if(x<=mid) res+=query(l,mid,x,y,ls,d-1);
    if(y>mid) res+=query(mid+1,r,x,y,rs,d-1);
    return res;
}

void solve()
{
    build(1,tot,1);
    while(q--)
    {
        int op=read();
        if(op==1)
        {
            int x=read();
            ll k=read();
            update(1,tot,x,k,1,n);
        }
        if(op==2)
        {
            int k=read();
            rep(i,0,k) c[i]^=1;
        }
        if(op==3)
        {
            int k=read();
            c[k+1]^=1;
        }
        if(op==4)
        {
            int x=read(),y=read();
            ll ans=query(1,tot,x,y,1,n);
            printf("%lld\n",ans);
        }
    }
}

int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    predo();
    //int cas=read();
    int cas=1;
    while(cas--)
    {
       init();
       solve();
    }
    return 0;
}


//orz Gold_7
//orz SqwrIwy
//orz yzh1505
//orz yzh2019
//orz new
//orz hejinfan
//orz chenkuowen
//#pragma comment(linker,?STACK:1677721600?
//#pragma GCC optimize("O2")
//#pragma G++ optimize("O2")
//#pragma GCC optimize("O3")
//#pragma G++ optimize("O3")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
//typedef __int128 ll;
typedef unsigned int uint;
typedef unsigned long long ull;
//typedef double db;
typedef long double ld;
typedef pair<int,int> PII;
typedef pair<ll,int> Pli;
typedef pair<ll,ll> Pll;
typedef vector<int> VI;
typedef vector<PII> VII;
//typedef pair<ll,ll>P;
#define fi first
#define se second
#define MP make_pair
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
#define per(i,a,b) for(int i=(int)a;i>=(int)b;i--)
#define REP(i,n) for(int i=0;i<n;++i)
#define lowbit(x) x&(-x)
#define Rand (rand()*(1<<16)+rand())
#define id(x) ((x)<=B?(x):m-n/(x)+1)
#define fors(i) for(auto i:e[x]) if(i!=p)
//#define ls p<<1
//#define rs p<<1|1

#define FI(n) FastIO::read(n)
#define FO(n) FastIO::write(n)
#define Flush FastIO::Fflush()

const int N=500010;
const int M=222222;
const int MOD=1e9+7;
const int intINF=int(1e9);
const ll llINF=ll(2e18);
const uint uintINF=~0U;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
const long double pi=acos(-1.0L);

int read()
{
   int v=0,f=1;
   char c=getchar();
   while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
   while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
   return v*f;
}

ll readll()
{
   ll v=0,f=1;
   char c=getchar();
   while(c<48||57<c) {if(c=='-') f=-1; c=getchar();}
   while(48<=c&&c<=57) v=(v<<3)+v+v+c-48,c=getchar();
   return v*f;
}

/*
void pr128(__int128 x)
{
    if(x<0) putchar('-'),x=-x;
    if(x<10) return putchar('0'+x),void();
    pr128(x/10),putchar('0'+(x%10));
}*/

/*namespace FastIO
{
    const int SIZE = 1 << 16;
    char buf[SIZE], obuf[SIZE], str[60];
    int bi = SIZE, bn = SIZE, opt;
    double D[] = {0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001, 0.0000000001};
    int read(char *s) {
        while (bn) {
            for (; bi < bn && buf[bi] <= ' '; bi++);
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        int sn = 0;
        while (bn) {
            for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        s[sn] = 0;
        return sn;
    }
    bool read(int& x) {
        int n = read(str), bf = 0;
        if (!n) return 0;
        int i = 0; if (str[i] == '-') bf = 1, i++; else if (str[i] == '+') i++;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf) x = -x;
        return 1;
    }
    bool read(long long& x) {
        int n = read(str), bf;
        if (!n) return 0;
        int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf < 0) x = -x;
        return 1;
    }
    void write(int x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            if (x < 0) obuf[opt++] = '-', x = -x;
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(long long x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            if (x < 0) obuf[opt++] = '-', x = -x;
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(unsigned long long x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(char x) {
        obuf[opt++] = x;
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void Fflush() { if (opt) fwrite(obuf, 1, opt, stdout); opt = 0;}
};

//int x=read();   ->int x; FI(x);*/

/*auto random_address = [] { char *p = new char; delete p; return uint64_t(p); };
const uint64_t SEED = chrono::steady_clock::now().time_since_epoch().count() * (random_address() | 1);
mt19937_64 rng(SEED);

ull SX=335634763,SY=873658265,SZ=192849106,SW=746126501;

inline ull xorshift128()
{
    ull t=SX^(SX<<11);
    SX=SY;
    SY=SZ;
    SZ=SW;
    return SW=SW^(SW>>19)^t^(t>>8);
}*/

void predo()
{
}

ll t[N<<2];
int a[N],c[20],n,q,tot;

void init()
{
    n=read(),q=read();
    tot=1<<n;
    rep(i,1,tot) a[i]=read();
}

void pushup(int p)
{
    t[p]=t[p<<1]+t[p<<1|1];
}

void build(int l,int r,int p)
{
    if(l==r)
    {
        t[p]=a[l];
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,p<<1);
    build(mid+1,r,p<<1|1);
    pushup(p);
}

void update(int l,int r,int x,ll y,int p,int d)
{
    if(x<=l&&r<=y)
    {
        t[p]=y;
        return;
    }
    int mid=(l+r)>>1;
    int ls=p<<1,rs=ls+1;
    if(c[d]) swap(ls,rs);
    if(x<=mid) update(l,mid,x,y,ls,d-1);
     else update(mid+1,r,x,y,rs,d-1);
    pushup(p);
}

ll query(int l,int r,int x,int y,int p,int d)
{
    if(x<=l&&r<=y) return t[p];
    int mid=(l+r)>>1;
    int ls=p<<1,rs=ls+1;
    if(c[d]) swap(ls,rs);
    ll res=0;
    if(x<=mid) res+=query(l,mid,x,y,ls,d-1);
    if(y>mid) res+=query(mid+1,r,x,y,rs,d-1);
    return res;
}

void solve()
{
    build(1,tot,1);
    while(q--)
    {
        int op=read();
        if(op==1)
        {
            int x=read(),k=read();
            update(1,tot,x,k,1,n);
        }
        if(op==2)
        {
            int k=read();
            rep(i,0,k) c[i]^=1;
        }
        if(op==3)
        {
            int k=read();
            c[k+1]^=1;
        }
        if(op==4)
        {
            int x=read(),y=read();
            ll ans=query(1,tot,x,y,1,n);
            printf("%lld\n",ans);
        }
    }
}

int main()
{
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);
    predo();
    //int cas=read();
    int cas=1;
    while(cas--)
    {
       init();
       solve();
    }
    return 0;
}


#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstring>
#include<climits>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define int LL
inline int read() {
	bool f=0;int x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c==EOF)exit(0);if(c=='-')f=1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return !f?x:-x;
}
#define lch (u<<1)
#define rch (u<<1|1)
#define MAXN 18
#define INF 0x3f3f3f3f
int swp[20];
LL sum[(1<<MAXN)+5];
void Build(int u,int L,int R){
	if(L==R){
		sum[u]=read();
		return ;
	}
	int Mid=(L+R)>>1;
	Build(lch,L,Mid),Build(rch,Mid+1,R);
	sum[u]=sum[lch]+sum[rch];
	return ;
}
void Modi(int u,int L,int R,int p,int val,int d){
	if(L==R){sum[u]=val;return ;}
	int Mid=(L+R)>>1,t=swp[d];
	if(p<=Mid) Modi(lch^t,L,Mid,p,val,d-1);
	else Modi(rch^t,Mid+1,R,p,val,d-1);
	sum[u]=sum[lch]+sum[rch];
	return ;
}
LL S(int u,int L,int R,int qL,int qR,int d){
	if(qL<=L&&R<=qR) return sum[u];
	LL ret=0;int Mid=(L+R)>>1,t=swp[d];
	if(qL<=Mid) ret+=S(lch^t,L,Mid,qL,qR,d-1);
	if(Mid+1<=qR) ret+=S(rch^t,Mid+1,R,qL,qR,d-1);
	return ret;
}
signed main(){
	int n=read(),q=read();
	Build(1,1,(1<<n));
	for(int i=1;i<=q;i++){
		int t=read();
		if(t==1){
			int x=read(),k=read();
			Modi(1,1,(1<<n),x,k,n);
		}
		else if(t==2){
			int k=read();
			for(int j=0;j<=k;j++)
				swp[j]^=1;
		}
		else if(t==3){
			int k=read();
			swp[k+1]^=1;
		}
		else{
			int L=read(),R=read();
			printf("%lld\n",S(1,1,(1<<n),L,R,n));
		}
	}
	return 0;
}


#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstring>
#include<climits>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define int LL
inline int read() {
	bool f=0;int x=0;char c=getchar();
	while(c<'0'||'9'<c){if(c==EOF)exit(0);if(c=='-')f=1;c=getchar();}
	while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return !f?x:-x;
}
#define lch (u<<1)
#define rch (u<<1|1)
#define MAXN 18
#define INF 0x3f3f3f3f
int swp[20];
LL sum[5*(1<<MAXN)+5];
void Build(int u,int L,int R){
	if(L==R){
		sum[u]=read();
		return ;
	}
	int Mid=(L+R)>>1;
	Build(lch,L,Mid),Build(rch,Mid+1,R);
	sum[u]=sum[lch]+sum[rch];
	return ;
}
void Modi(int u,int L,int R,int p,int val,int d){
	if(L==R){sum[u]=val;return ;}
	int Mid=(L+R)>>1,t=swp[d];
	if(p<=Mid) Modi(lch^t,L,Mid,p,val,d-1);
	else Modi(rch^t,Mid+1,R,p,val,d-1);
	sum[u]=sum[lch]+sum[rch];
	return ;
}
LL S(int u,int L,int R,int qL,int qR,int d){
	if(qL<=L&&R<=qR) return sum[u];
	LL ret=0;int Mid=(L+R)>>1,t=swp[d];
	if(qL<=Mid) ret+=S(lch^t,L,Mid,qL,qR,d-1);
	if(Mid+1<=qR) ret+=S(rch^t,Mid+1,R,qL,qR,d-1);
	return ret;
}
signed main(){
	int n=read(),q=read();
	Build(1,1,(1<<n));
	for(int i=1;i<=q;i++){
		int t=read();
		if(t==1){
			int x=read(),k=read();
			Modi(1,1,(1<<n),x,k,n);
		}
		else if(t==2){
			int k=read();
			for(int j=0;j<=k;j++)
				swp[j]^=1;
		}
		else if(t==3){
			int k=read();
			swp[k+1]^=1;
		}
		else{
			int L=read(),R=read();
			printf("%lld\n",S(1,1,(1<<n),L,R,n));
		}
	}
	return 0;
}


#include<bits/stdc++.h>
#define REG register
using namespace std;
inline int read(){
	static char c;static int x=0;
	while(!isdigit(c=getchar()));x=c^48;
	while(isdigit(c=getchar()))x=(x*10)+(c^48);
	return x;
}

typedef long long ll;

const int N=263051;

int _n,n,q;

int A[N],Rev[N];

struct Segment{
	ll t[N<<2];
	#define mid ((l+r)>>1)
	void Init(int Now,int l,int r){
		if(l==r){t[Now]=A[l];return;}
		Init(Now<<1,l,mid),Init(Now<<1|1,mid+1,r);
		t[Now]=t[Now<<1]+t[Now<<1|1];
	}
	void Rpl(int Now,int d,int l,int r,int pos,int x){
		if(l==r){t[Now]=x;return;}
		int L=Now<<1,R=Now<<1|1;
		if(Rev[d]) swap(L,R);
		if(mid>=pos) Rpl(L,d-1,l,mid,pos,x);
		else Rpl(R,d-1,mid+1,r,pos,x);
		t[Now]=t[L]+t[R];
	}
	ll Ask(int Now,int d,int l,int r,int x,int y){
		if(l>=x&&r<=y) return t[Now];
		int L=Now<<1,R=Now<<1|1;ll res=0;
		if(Rev[d]) swap(L,R);
		if(mid>=x) res+=Ask(L,d-1,l,mid,x,y);
		if(mid<y) res+=Ask(R,d-1,mid+1,r,x,y);
		return res;
	}
}T;

inline void Work(){
	_n=read(),n=1<<_n,q=read();
	for(REG int i=1;i<=n;++i) A[i]=read();
	T.Init(1,1,n);
	while(q--){
		int opt=read(),x,y;
		if(opt==1) x=read(),y=read(),T.Rpl(1,_n,1,n,x,y);
		if(opt==2){x=read();for(REG int i=0;i<=x;++i)Rev[i]^=1;}
		if(opt==3) x=read(),Rev[x+1]^=1;
		if(opt==4) x=read(),y=read(),printf("%lld\n",T.Ask(1,_n,1,n,x,y));
	}
}

int main(){Work();}


#include<bits/stdc++.h>
#define REG register
using namespace std;
inline void read(int& x){
	static char c;
	while(!isdigit(c=getchar()));x=c^48;
	while(isdigit(c=getchar()))x=(x*10)+(c^48);
}

typedef long long ll;

const int N=262150;

int _n,n,q;

int A[N];

struct Segment_Tree{
	struct Tree{ll Val;int Lson,Rson,Tag;}t[N<<2];
	#define Ls(x) (t[x].Lson)
	#define Rs(x) (t[x].Rson)
	#define mid ((l+r)>>1)

	void Init(int Now,int l,int r){
		if(l==r){t[Now].Val=A[l];return;}
		Init(Ls(Now)=(Now<<1),l,mid),Init(Rs(Now)=(Now<<1|1),mid+1,r);
		t[Now].Val=t[Ls(Now)].Val+t[Rs(Now)].Val;
	}

	void Pushdown(int Now){if(t[Now].Tag)swap(Ls(Ls(Now)),Rs(Ls(Now))),t[Ls(Now)].Tag^=1,swap(Ls(Rs(Now)),Rs(Rs(Now))),t[Rs(Now)].Tag^=1,t[Now].Tag=0;}

	void Update(int Now,int l,int r,int pos,int add){
		if(l==r){t[Now].Val=add;return;}
		Pushdown(Now);
		if(mid>=pos) Update(Ls(Now),l,mid,pos,add);
		else Update(Rs(Now),mid+1,r,pos,add);
		t[Now].Val=t[Ls(Now)].Val+t[Rs(Now)].Val;
	}

	void Reverse(int Now){t[Now].Tag^=1,swap(Ls(Now),Rs(Now));}
	void Swap(int Now){swap(Ls(Now),Rs(Now));}

	ll Ask(int Now,int l,int r,int x,int y){
		if(l>=x&&r<=y) return t[Now].Val;
		Pushdown(Now);ll res=0;
		if(mid>=x) res+=Ask(Ls(Now),l,mid,x,y);
		if(mid<y) res+=Ask(Rs(Now),mid+1,r,x,y);
		return res;
	}
}T;

inline void Work(){
	read(_n),read(q);n=1<<_n;
	for(REG int i=1;i<=n;++i) read(A[i]);T.Init(1,1,n);
	while(q--){
		int opt,x,y;read(opt);
		if(opt==1) read(x),read(y),T.Update(1,1,n,x,y);
		if(opt==2){read(x);for(REG int i=(1<<(_n-x));i<(1<<(_n-x+1));++i)T.Reverse(i);}
		if(opt==3){read(x);for(REG int i=(1<<(_n-x-1));i<(1<<(_n-x));++i)T.Swap(i);}
		if(opt==4) read(x),read(y),printf("%lld\n",T.Ask(1,1,n,x,y));
	}
}

int main(){Work();}


#include<bits/stdc++.h>
#define REG register
using namespace std;
inline int read(){
	static char c;static int x=0;
	while(!isdigit(c=getchar()));x=c^48;
	while(isdigit(c=getchar()))x=(x*10)+(c^48);
	return x;
}

typedef long long ll;

const int N=263050;

int _n,n,q;

int A[N],Rev[N];

struct Segment{
	ll t[N<<2];
	#define mid ((l+r)>>1)
	void Init(int Now,int l,int r){
		if(l==r){t[Now]=A[l];return;}
		Init(Now<<1,l,mid),Init(Now<<1|1,mid+1,r);
		t[Now]=t[Now<<1]+t[Now<<1|1];
	}
	void Rpl(int Now,int d,int l,int r,int pos,int x){
		if(l==r){t[Now]=x;return;}
		int L=Now<<1,R=Now<<1|1;
		if(Rev[d]) swap(L,R);
		if(mid>=pos) Rpl(L,d-1,l,mid,pos,x);
		else Rpl(R,d-1,mid+1,r,pos,x);
		t[Now]=t[L]+t[R];
	}
	ll Ask(int Now,int d,int l,int r,int x,int y){
		if(l>=x&&r<=y) return t[Now];
		int L=Now<<1,R=Now<<1|1;ll res=0;
		if(Rev[d]) swap(L,R);
		if(mid>=x) res+=Ask(L,d-1,l,mid,x,y);
		if(mid<y) res+=Ask(R,d-1,mid+1,r,x,y);
		return res;
	}
}T;

inline void Work(){
	_n=read(),n=1<<_n,q=read();
	for(REG int i=1;i<=n;++i) A[i]=read();
	T.Init(1,1,n);
	while(q--){
		int opt=read(),x,y;
		if(opt==1) x=read(),y=read(),T.Rpl(1,_n,1,n,x,y);
		if(opt==2){x=read();for(REG int i=0;i<=x;++i)Rev[i]^=1;}
		if(opt==3) x=read(),Rev[x+1]^=1;
		if(opt==4) x=read(),y=read(),printf("%lld\n",T.Ask(1,_n,1,n,x,y));
	}
}

int main(){Work();}


#include<bits/stdc++.h>
#define REG register
using namespace std;
inline int read(){
	static char c;static int x=0;
	while(!isdigit(c=getchar()));x=c^48;
	while(isdigit(c=getchar()))x=(x*10)+(c^48);
	return x;
}

typedef long long ll;

const int N=261050;

int _n,n,q;

int A[N],Rev[N];

struct Segment{
	ll t[N<<2];
	#define mid ((l+r)>>1)
	void Init(int Now,int l,int r){
		if(l==r){t[Now]=A[l];return;}
		Init(Now<<1,l,mid),Init(Now<<1|1,mid+1,r);
		t[Now]=t[Now<<1]+t[Now<<1|1];
	}
	void Rpl(int Now,int d,int l,int r,int pos,int x){
		if(l==r){t[Now]=x;return;}
		int L=Now<<1,R=Now<<1|1;
		if(Rev[d]) swap(L,R);
		if(mid>=pos) Rpl(L,d-1,l,mid,pos,x);
		else Rpl(R,d-1,mid+1,r,pos,x);
		t[Now]=t[L]+t[R];
	}
	ll Ask(int Now,int d,int l,int r,int x,int y){
		if(l>=x&&r<=y) return t[Now];
		int L=Now<<1,R=Now<<1|1;ll res=0;
		if(Rev[d]) swap(L,R);
		if(mid>=x) res+=Ask(L,d-1,l,mid,x,y);
		if(mid<y) res+=Ask(R,d-1,mid+1,r,x,y);
		return res;
	}
}T;

inline void Work(){
	_n=read(),n=1<<_n,q=read();
	for(REG int i=1;i<=n;++i) A[i]=read();
	T.Init(1,1,n);
	while(q--){
		int opt=read(),x,y;
		if(opt==1) x=read(),y=read(),T.Rpl(1,_n,1,n,x,y);
		if(opt==2){x=read();for(REG int i=0;i<=x;++i)Rev[i]^=1;}
		if(opt==3) x=read(),Rev[x+1]^=1;
		if(opt==4) x=read(),y=read(),printf("%lld\n",T.Ask(1,_n,1,n,x,y));
	}
}

int main(){Work();}


#include<bits/stdc++.h>
#define REG register
using namespace std;
inline void read(int& x){
	static char c;
	while(!isdigit(c=getchar()));x=c^48;
	while(isdigit(c=getchar()))x=(x*10)+(c^48);
}

typedef long long ll;

const int N=262150;

int _n,n,q;

int A[N];

struct Segment_Tree{
	struct Tree{ll Val;int Lson,Rson,Tag;}t[N<<2];
	#define Ls(x) (t[x].Lson)
	#define Rs(x) (t[x].Rson)
	#define mid ((l+r)>>1)

	void Init(int Now,int l,int r){
		if(l==r){t[Now].Val=A[l];return;}
		Init(Ls(Now)=(Now<<1),l,mid),Init(Rs(Now)=(Now<<1|1),mid+1,r);
		t[Now].Val=t[Ls(Now)].Val+t[Rs(Now)].Val;
	}

	void Pushdown(int Now){if(t[Now].Tag)swap(Ls(Now),Rs(Now)),t[Ls(Now)].Tag^=1,t[Rs(Now)].Tag^=1,t[Now].Tag=0;}

	void Update(int Now,int l,int r,int pos,int add){
		if(l==r){t[Now].Val=add;return;}
		Pushdown(Now);
		if(mid>=pos) Update(Ls(Now),l,mid,pos,add);
		else Update(Rs(Now),mid+1,r,pos,add);
		t[Now].Val=t[Ls(Now)].Val+t[Rs(Now)].Val;
	}

	void Reverse(int Now){t[Now].Tag^=1,swap(Ls(Now),Rs(Now));}
	void Swap(int Now){swap(Ls(Now),Rs(Now));}

	ll Ask(int Now,int l,int r,int x,int y){
		if(l>=x&&r<=y) return t[Now].Val;
		Pushdown(Now);ll res=0;
		if(mid>=x) res+=Ask(Ls(Now),l,mid,x,y);
		if(mid<y) res+=Ask(Rs(Now),mid+1,r,x,y);
		return res;
	}
}T;

inline void Work(){
	read(_n),read(q);n=1<<_n;
	for(REG int i=1;i<=n;++i) read(A[i]);T.Init(1,1,n);
	while(q--){
		int opt,x,y;read(opt);
		if(opt==1) read(x),read(y),T.Update(1,1,n,x,y);
		if(opt==2){read(x);for(REG int i=(1<<(_n-x));i<(1<<(_n-x+1));++i)T.Reverse(i);}
		if(opt==3){read(x);for(REG int i=(1<<(_n-x-1));i<(1<<(_n-x));++i)T.Swap(i);}
		if(opt==4) read(x),read(y),printf("%lld\n",T.Ask(1,1,n,x,y));
	}
}

int main(){Work();}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int a[N], lg[N], re[20], sw[20];
ll sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    // int dep = lg[r-l+1];
    // int pos = r/(r-l+1)-1;
    // for(int i=n; i>=dep; i--) {
    //     int k = 1<<(i-dep);
    //     if(re[i]) {
    //         int lp = pos/k*k;
    //         pos = 2*lp+k-1-pos;
    //     }
    //     if(sw[i]) {
    //         int t = pos/k;
    //         if(t&1)
    //             pos -= k;
    //         else
    //             pos += k;
    //     }
    // }
    // return idx[dep][pos];
    int d = r-l+1, p = r/d-1, x = lg[d];
    for(int i=x; i<n; i++) {
        if(sw[i])
            p ^= 1<<(i-x);
    }
    for(int i=x+1; i<=n; i++) {
        if(re[i])
            p ^= (1<<(i-x))-1;
    }
    return idx[x][p];
}

ll query(int o, int l, int r, int L, int R) {
    // printf("l=%d r=%d\n", l, r);
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%d", &a[i]);
    build(1, 1, 1<<n);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            // int o = calc(x, x);
            // while(o>=1) {
            //     sumv[o] += k-a[x];
            //     o >>= 1;
            // }
            // a[x] = k;
            x--;
            for(int i=0; i<n; i++) {
                if(sw[i])
                    x ^= 1<<i;
            }
            for(int i=1; i<=n; i++) {
                if(re[i])
                    x ^= (1<<i)-1;
            }
            int d = k-sumv[idx[0][x]];
            for(int j=0; j<=n; j++)
                sumv[idx[j][x>>j]] += d;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            re[k] ^= 1;
            // for(int i=k-1; i>=0; i--)
            //     sw[i] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    // for(int i=0; i<=n; i++) {
    //     for(int j: idx[i])
    //         printf("%d ", sumv[j]);
    //     printf("\n");
    // }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int a[N], lg[N], re[20], sw[20];
ll sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    int dep = lg[r-l+1];
    int pos = r/(r-l+1)-1;
    for(int i=n; i>=dep; i--) {
        int k = 1<<(i-dep);
        if(re[i]) {
            int lp = pos/k*k;
            pos = 2*lp+k-1-pos;
        }
        if(sw[i]) {
            int t = pos/k;
            if(t&1)
                pos -= k;
            else
                pos += k;
        }
    }
    return idx[dep][pos];
}

ll query(int o, int l, int r, int L, int R) {
    // printf("l=%d r=%d\n", l, r);
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%d", &a[i]);
    build(1, 1, 1<<n);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            int o = calc(x, x);
            while(o>=1) {
                sumv[o] += k-a[x];
                o >>= 1;
            }
            a[x] = k;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            re[k] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    // for(int i=0; i<=n; i++) {
    //     for(int j: idx[i])
    //         printf("%d ", sumv[j]);
    //     printf("\n");
    // }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int a[N], lg[N], re[20], sw[20];
ll sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    int dep = lg[r-l+1];
    int pos = r/(r-l+1)-1;
    for(int i=n; i>=dep; i--) {
        int k = 1<<(i-dep);
        if(re[i]) {
            int lp = pos/k*k;
            pos = 2*lp+k-1-pos;
        }
        if(sw[i]) {
            int t = pos/k;
            if(t&1)
                pos -= k;
            else
                pos += k;
        }
    }
    return idx[dep][pos];
    // int d = r-l+1, p = r/d-1, x = lg[d];
    // for(int i=x; i<n; i++) {
    //     if(sw[i])
    //         p ^= 1<<(i-x);
    // }
    // for(int i=x+1; i<=n; i++) {
    //     if(re[i])
    //         p ^= (1<<(i-x))-1;
    // }
    // return idx[x][p];
}

ll query(int o, int l, int r, int L, int R) {
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%d", &a[i]);
    build(1, 1, 1<<n);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            int o = calc(x, x);
            int d = k-sumv[o];
            while(o>=1) {
                sumv[o] += d;
                o >>= 1;
            }
            // x--;
            // for(int i=0; i<n; i++) {
            //     if(sw[i])
            //         x ^= 1<<i;
            // }
            // for(int i=1; i<=n; i++) {
            //     if(re[i])
            //         x ^= (1<<i)-1;
            // }
            // int d = k-sumv[idx[0][x]];
            // for(int j=0; j<=n; j++)
            //     sumv[idx[j][x>>j]] += d;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            re[k] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int a[N], lg[N], re[20], sw[20];
ll sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    // int dep = lg[r-l+1];
    // int pos = r/(r-l+1)-1;
    // for(int i=n; i>=dep; i--) {
    //     int k = 1<<(i-dep);
    //     if(re[i]) {
    //         int lp = pos/k*k;
    //         pos = 2*lp+k-1-pos;
    //     }
    //     if(sw[i]) {
    //         int t = pos/k;
    //         if(t&1)
    //             pos -= k;
    //         else
    //             pos += k;
    //     }
    // }
    // return idx[dep][pos];
    int d = r-l+1, p = r/d-1, x = lg[d];
    for(int i=x; i<n; i++) {
        if(sw[i])
            p ^= 1<<(i-x);
    }
    for(int i=x+1; i<=n; i++) {
        if(re[i])
            p ^= (1<<(i-x))-1;
    }
    return idx[x][p];
}

ll query(int o, int l, int r, int L, int R) {
    // printf("l=%d r=%d\n", l, r);
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%d", &a[i]);
    build(1, 1, 1<<n);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            int o = calc(x, x);
            while(o>=1) {
                sumv[o] += k-a[x];
                o >>= 1;
            }
            a[x] = k;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            // re[k] ^= 1;
            for(int i=k-1; i>=0; i--)
                sw[i] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    // for(int i=0; i<=n; i++) {
    //     for(int j: idx[i])
    //         printf("%d ", sumv[j]);
    //     printf("\n");
    // }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int a[N], lg[N], re[20], sw[20];
ll sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    int dep = lg[r-l+1];
    int pos = r/(r-l+1)-1;
    for(int i=n; i>=dep; i--) {
        int k = 1<<(i-dep);
        if(re[i]) {
            int lp = pos/k*k;
            pos = 2*lp+k-1-pos;
        }
        if(sw[i]) {
            int t = pos/k;
            if(t&1)
                pos -= k;
            else
                pos += k;
        }
    }
    return idx[dep][pos];
}

ll query(int o, int l, int r, int L, int R) {
    // printf("l=%d r=%d\n", l, r);
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%d", &a[i]);
    build(1, 1, 1<<n);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            int o = calc(x, x);
            while(o>=1) {
                sumv[o] += k-a[x];
                o >>= 1;
            }
            a[x] = k;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            // re[k] ^= 1;
            for(int i=k-1; i>=0; i--)
                sw[i] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    // for(int i=0; i<=n; i++) {
    //     for(int j: idx[i])
    //         printf("%d ", sumv[j]);
    //     printf("\n");
    // }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int lg[N], re[20], sw[20];
ll a[N], sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    int dep = lg[r-l+1];
    int pos = r/(r-l+1)-1;
    for(int i=n; i>=dep; i--) {
        int k = 1<<(i-dep);
        if(re[i]) {
            int lp = pos/k*k;
            pos = 2*lp+k-1-pos;
        }
        if(sw[i]) {
            int t = pos/k;
            if(t&1)
                pos -= k;
            else
                pos += k;
        }
    }
    return idx[dep][pos];
}

ll query(int o, int l, int r, int L, int R) {
    // printf("l=%d r=%d\n", l, r);
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%lld", &a[i]);
    build(1, 1, 1<<n);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            int o = calc(x, x);
            while(o>=1) {
                sumv[o] += k-a[x];
                o >>= 1;
            }
            a[x] = k;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            re[k] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    // for(int i=0; i<=n; i++) {
    //     for(int j: idx[i])
    //         printf("%d ", sumv[j]);
    //     printf("\n");
    // }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int a[N], lg[N], re[20], sw[20];
ll sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    // int dep = lg[r-l+1];
    // int pos = r/(r-l+1)-1;
    // for(int i=n; i>=dep; i--) {
    //     int k = 1<<(i-dep);
    //     if(re[i]) {
    //         int lp = pos/k*k;
    //         pos = 2*lp+k-1-pos;
    //     }
    //     if(sw[i]) {
    //         int t = pos/k;
    //         if(t&1)
    //             pos -= k;
    //         else
    //             pos += k;
    //     }
    // }
    // return idx[dep][pos];
    int d = r-l+1, p = r/d-1, x = lg[d];
    for(int i=x; i<n; i++) {
        if(sw[i])
            p ^= 1<<(i-x);
    }
    for(int i=x+1; i<=n; i++) {
        if(re[i])
            p ^= (1<<(i-x))-1;
    }
    return idx[x][p];
}

ll query(int o, int l, int r, int L, int R) {
    // printf("l=%d r=%d\n", l, r);
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%d", &a[i]);
    build(1, 1, 1<<n);
    for(int i=0; i<=n; i++)
        sort(idx[i].begin(), idx[i].end());
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            int o = calc(x, x);
            while(o>=1) {
                sumv[o] += k-a[x];
                o >>= 1;
            }
            a[x] = k;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            // re[k] ^= 1;
            for(int i=k-1; i>=0; i--)
                sw[i] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    // for(int i=0; i<=n; i++) {
    //     for(int j: idx[i])
    //         printf("%d ", sumv[j]);
    //     printf("\n");
    // }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int a[N], lg[N], re[20], sw[20];
ll sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    // int dep = lg[r-l+1];
    // int pos = r/(r-l+1)-1;
    // for(int i=n; i>=dep; i--) {
    //     int k = 1<<(i-dep);
    //     if(re[i]) {
    //         int lp = pos/k*k;
    //         pos = 2*lp+k-1-pos;
    //     }
    //     if(sw[i]) {
    //         int t = pos/k;
    //         if(t&1)
    //             pos -= k;
    //         else
    //             pos += k;
    //     }
    // }
    // return idx[dep][pos];
    int d = r-l+1, p = r/d-1, x = lg[d];
    for(int i=x; i<n; i++) {
        if(sw[i])
            p ^= 1<<(i-x);
    }
    for(int i=x+1; i<=n; i++) {
        if(re[i])
            p ^= (1<<(i-x))-1;
    }
    return idx[x][p];
}

ll query(int o, int l, int r, int L, int R) {
    // printf("l=%d r=%d\n", l, r);
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%d", &a[i]);
    build(1, 1, 1<<n);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            int o = calc(x, x);
            while(o>=1) {
                sumv[o] += k-a[x];
                o >>= 1;
            }
            a[x] = k;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            re[k] ^= 1;
            // for(int i=k-1; i>=0; i--)
            //     sw[i] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    // for(int i=0; i<=n; i++) {
    //     for(int j: idx[i])
    //         printf("%d ", sumv[j]);
    //     printf("\n");
    // }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1<<19;

int n, q;
int a[N], lg[N], re[20], sw[20];
ll sumv[N<<2];
vector<int> idx[20];

void build(int o, int l, int r) {
    idx[lg[r-l+1]].push_back(o);
    if(l==r) {
        sumv[o] = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    sumv[o] = sumv[o<<1]+sumv[o<<1|1];
}

int calc(int l, int r) {
    int dep = lg[r-l+1];
    int pos = r/(r-l+1)-1;
    for(int i=n; i>=dep; i--) {
        int k = 1<<(i-dep);
        if(re[i]) {
            int lp = pos/k*k;
            pos = 2*lp+k-1-pos;
        }
        if(sw[i]) {
            int t = pos/k;
            if(t&1)
                pos -= k;
            else
                pos += k;
        }
    }
    return idx[dep][pos];
    // int d = r-l+1, p = r/d-1, x = lg[d];
    // for(int i=x; i<n; i++) {
    //     if(sw[i])
    //         p ^= 1<<(i-x);
    // }
    // for(int i=x+1; i<=n; i++) {
    //     if(re[i])
    //         p ^= (1<<(i-x))-1;
    // }
    // return idx[x][p];
}

ll query(int o, int l, int r, int L, int R) {
    // printf("l=%d r=%d\n", l, r);
    if(L<=l && R>=r)
        return sumv[calc(l, r)];
    int mid = (l+r)>>1;
    ll res = 0;
    if(L<=mid)
        res += query(o<<1, l, mid, L, R);
    if(R>mid)
        res += query(o<<1|1, mid+1, r, L, R);
    return res;
}

int main() {
    scanf("%d%d", &n, &q);
    for(int i=0; (1<<i)<N; i++)
        lg[1<<i] = i;
    for(int i=1; i<=(1<<n); i++)
        scanf("%d", &a[i]);
    build(1, 1, 1<<n);
    while(q--) {
        int op;
        scanf("%d", &op);
        if(op==1) {
            int x, k;
            scanf("%d%d", &x, &k);
            // int o = calc(x, x);
            // while(o>=1) {
            //     sumv[o] += k-a[x];
            //     o >>= 1;
            // }
            // a[x] = k;
            x--;
            for(int i=0; i<n; i++) {
                if(sw[i])
                    x ^= 1<<i;
            }
            for(int i=1; i<=n; i++) {
                if(re[i])
                    x ^= (1<<i)-1;
            }
            int d = k-sumv[idx[0][x]];
            for(int j=0; j<=n; j++)
                sumv[idx[j][x>>j]] += d;
        }
        else if(op==2) {
            int k;
            scanf("%d", &k);
            re[k] ^= 1;
            // for(int i=k-1; i>=0; i--)
            //     sw[i] ^= 1;
        }
        else if(op==3) {
            int k;
            scanf("%d", &k);
            sw[k] ^= 1;
        }
        else {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%lld\n", query(1, 1, 1<<n, l, r));
        }
    }
    // for(int i=0; i<=n; i++) {
    //     for(int j: idx[i])
    //         printf("%d ", sumv[j]);
    //     printf("\n");
    // }
    return 0;
}


#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <vector>

using std::vector;

typedef long long Int;

constexpr Int kDirty = 10000000000000000ll;

class SegmentTree {
 public:
  SegmentTree(const vector<Int>& xs) : n_(xs.size()) {
    const auto k = static_cast<int>(1 + std::log2(n_));
    rev_.resize(k, false);
    swap_.resize(k, false);

    BuildTree_(xs);
  }

  void Replace(const int x, Int value) {
    if (n_ == 1) {
      tree_[0] = value;
      return;
    }

    int n = n_;
    int xx = x;
    int i = 0;

    // Add value.
    do {
      const int m = n / 2;
      const auto left = xx < m;
      i = left ? LChild_(i) : RChild_(i);
      if (!left) {
        xx -= m;
      }
      n -= m;
    } while (n > 1);
    // std::cout << i << ", " << tree_[i] << std::endl;
    tree_[i] = value;

    // Adjust tree.
    do {
      i = Parent_(i);
      // std::cout << i << ", " << LChild_(i) << ", " << RChild_(i) << std::endl;
      tree_[i] = tree_[LChild_(i)] + tree_[RChild_(i)];
    } while (i > 0);
  }

  void Print() const {
    std::cout << "=================" << std::endl;
    for (int i = 0; i < n_; ++i) {
      std::cout << Sum(i, i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < tree_.size(); ++i) {
      std::cout << tree_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < rev_.size(); ++i) {
      std::cout << rev_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < swap_.size(); ++i) {
      std::cout << swap_.at(i) << ", ";
    }
    std::cout << std::endl;
    std::cout << "=================" << std::endl;
  }

  void Reverse(int k) {
    for (int t = rev_.size()-k-1; t < rev_.size(); ++t) {
      rev_[t] = !rev_[t];
    }
  }

  void Swap(int k) {
    // if (k >= swap_.size()) return;
    swap_[swap_.size()-k-2] = !swap_[swap_.size()-k-2];
  }

  Int Sum(int l, int r) const {
    return Ssum_(l, r, 0, 0, n_-1);
  }

 private:
  Int Level_(int i) const { return static_cast<Int>(std::log2(1+i)); }
  Int Parent_(int i) const { return i <= 0 ? 0 : (i-1) / 2; }
  Int LChild_(int i) const {
    const int level = Level_(i);
    const bool x = rev_[level] != swap_[level];
    return 2*i+1+x;
  }
  Int RChild_(int i) const {
    const int level = Level_(i);
    const bool x = rev_[level] == swap_[level];
    return 2*i+1+x;
  }

  Int Ssum_(int l, int r, int i, int ll, int rr) const {
    if (l > r || ll > rr) return 0;
    if (!(ll <= l && r <= rr)) return 0;
    if (l == ll && r == rr) return tree_.at(i);
    const int m = (ll+rr)/2;
    // std::cout << "l=" << l << ", m=" << m << ", r=" << r << ", ll=" << ll << ", rr=" << rr << std::endl;
    return Ssum_(l, std::min(r, m), LChild_(i), ll, m) + Ssum_(std::max(l, m+1), r, RChild_(i), m+1, rr);
  }

  void BuildTree_(const vector<Int>& xs) {
    tree_.resize(2*xs.size()-1, kDirty);

    for (int i = 0; i < xs.size(); ++i) {
      tree_.at(tree_.size()-xs.size()+i) = xs.at(i);
    }

    Sum_(0);
  }

  Int Sum_(int i) {
    if (LChild_(i) >= tree_.size()) return tree_.at(i);
    tree_.at(i) = Sum_(LChild_(i)) + Sum_(RChild_(i));
    return tree_.at(i);
  }

 private:
  vector<Int> tree_;
  const int n_;
  vector<bool> rev_;
  vector<bool> swap_;
};

int mmain() {
  vector<Int> xs = {1};
  SegmentTree st(xs);
  st.Print();
  // st.Replace(0, 10);
  // st.Replace(1, 10);
  // st.Replace(2, 10);
  // st.Replace(3, 10);
  // st.Replace(4, 10);
  // st.Replace(5, 10);
  // st.Replace(6, 10);
  st.Replace(0, 10);
  st.Print();
  std::cout << st.Sum(0, 0) << std::endl;
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(0);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(1);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(3);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(0);
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(1);

  return 0;
}

int main() {
  int n, q;
  std::cin >> n >> q;

  vector<Int> xs(1 << n);
  for (int i = 0; i < (1 << n); ++i) {
    std::cin >> xs[i];
  }
  SegmentTree st(xs);

  while (q --> 0) {
    int c;
    std::cin >> c;

    Int k;
    switch (c) {
      case 1:
        int x;
        std::cin >> x >> k;
        st.Replace(x-1, k);
        break;
      case 2:
        std::cin >> k;
        st.Reverse(k);
        break;
      case 3:
        std::cin >> k;
        st.Swap(k);
        break;
      case 4:
        int l, r;
        std::cin >> l >> r;
        std::cout << st.Sum(l-1, r-1) << std::endl;
        break;
      default:
        break;
    }
    // st.Print();
  }

  return 0;
}


#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <vector>

using std::vector;

typedef long long Int;

constexpr Int kDirty = 10000000000000000ll;

class SegmentTree {
 public:
  SegmentTree(const vector<Int>& xs) : n_(xs.size()) {
    const auto k = static_cast<int>(std::log2(n_));
    rev_.resize(k, false);
    swap_.resize(k, false);

    BuildTree_(xs);
  }

  void Replace(const int x, Int value) {
    int n = n_;
    int xx = x;
    int i = 0;

    // Add value.
    do {
      const int m = n / 2;
      const auto left = xx < m;
      i = left ? LChild_(i) : RChild_(i);
      if (!left) {
        xx -= m;
      }
      n -= m;
    } while (n > 1);
    tree_[i] = value;

    // Adjust tree.
    do {
      i = Parent_(i);
      tree_[i] = tree_[LChild_(i)] + tree_[RChild_(i)];
    } while (i > 0);
  }

  void Print() {
    std::cout << "=================" << std::endl;
    for (int i = 0; i < n_; ++i) {
      std::cout << Sum(i, i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < tree_.size(); ++i) {
      std::cout << tree_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < rev_.size(); ++i) {
      std::cout << rev_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < swap_.size(); ++i) {
      std::cout << swap_.at(i) << ", ";
    }
    std::cout << std::endl;
    std::cout << "=================" << std::endl;
  }

  void Reverse(int k) {
    for (int t = rev_.size()-k; t < rev_.size(); ++t) {
      rev_[t] = !rev_[t];
    }
  }

  void Swap(int k) {
    if (k >= swap_.size()) return;
    swap_[swap_.size()-k-1] = !swap_[swap_.size()-k-1];
  }

  Int Sum(int l, int r) {
    return Ssum_(l, r, 0, 0, n_-1);
  }

 private:
  Int Level_(int i) { return static_cast<Int>(std::log2(1+i)); }
  Int Parent_(int i) { return i / 2; }
  Int LChild_(int i) {
    const int level = Level_(i);
    const bool x = rev_[level] != swap_[level];
    return 2*i+1+x;
  }
  Int RChild_(int i) {
    const int level = Level_(i);
    const bool x = rev_[level] == swap_[level];
    return 2*i+1+x;
  }

  Int Ssum_(int l, int r, int i, int ll, int rr) {
    if (l > r || ll > rr) return 0;
    if (!(ll <= l && r <= rr)) return 0;
    if (l == ll && r == rr) return tree_.at(i);
    const int m = (ll+rr)/2;
    // std::cout << "l=" << l << ", m=" << m << ", r=" << r << ", ll=" << ll << ", rr=" << rr << std::endl;
    return Ssum_(l, std::min(r, m), LChild_(i), ll, m) + Ssum_(std::max(l, m+1), r, RChild_(i), m+1, rr);
  }

  void BuildTree_(const vector<Int>& xs) {
    tree_.resize(2*xs.size()-1, kDirty);

    for (int i = 0; i < xs.size(); ++i) {
      tree_.at(tree_.size()-xs.size()+i) = xs.at(i);
    }

    Sum_(0);
  }

  Int Sum_(int i) {
    if (LChild_(i) >= tree_.size()) return tree_.at(i);
    tree_.at(i) = Sum_(LChild_(i)) + Sum_(RChild_(i));
    return tree_.at(i);
  }

 private:
  vector<Int> tree_;
  const int n_;
  vector<bool> rev_;
  vector<bool> swap_;
};

int mmain() {
  vector<Int> xs = {1, 2, 3, 10, 5, 6, 7, 8};
  SegmentTree st(xs);
  st.Print();
  st.Replace(3, 4);
  st.Print();
  st.Reverse(3);
  st.Replace(3, 420);
  st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(0);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(1);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(3);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(0);
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(1);

  return 0;
}

int main() {
  int n, q;
  std::cin >> n >> q;

  vector<Int> xs(1 << n);
  for (int i = 0; i < (1 << n); ++i) {
    std::cin >> xs[i];
  }
  SegmentTree st(xs);

  while (q --> 0) {
    int c;
    std::cin >> c;

    Int k;
    switch (c) {
      case 1:
        int x;
        std::cin >> x >> k;
        st.Replace(x-1, k);
        break;
      case 2:
        std::cin >> k;
        st.Reverse(k);
        break;
      case 3:
        std::cin >> k;
        st.Swap(k);
        break;
      case 4:
        int l, r;
        std::cin >> l >> r;
        std::cout << st.Sum(l-1, r-1) << std::endl;
        break;
      default:
        break;
    }
    // st.Print();
  }

  return 0;
}


#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <vector>

using std::vector;

typedef long long Int;

constexpr Int kDirty = 10000000000000000ll;

class SegmentTree {
 public:
  SegmentTree(const vector<Int>& xs) : n_(xs.size()) {
    const auto k = static_cast<int>(std::log2(n_));
    rev_.resize(k, false);
    swap_.resize(k, false);

    BuildTree_(xs);
  }

  void Replace(const int x, Int value) {
    int n = n_;
    int xx = x;
    int i = 0;

    // Add value.
    do {
      const int m = n / 2;
      const auto left = xx < m;
      i = left ? LChild_(i) : RChild_(i);
      if (!left) {
        xx -= m;
      }
      n -= m;
    } while (n > 1);
    // std::cout << i << ", " << tree_[i] << std::endl;
    tree_[i] = value;

    // Adjust tree.
    do {
      i = Parent_(i);
      // std::cout << i << ", " << LChild_(i) << ", " << RChild_(i) << std::endl;
      tree_[i] = tree_[LChild_(i)] + tree_[RChild_(i)];
    } while (i > 0);
  }

  void Print() const {
    std::cout << "=================" << std::endl;
    for (int i = 0; i < n_; ++i) {
      std::cout << Sum(i, i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < tree_.size(); ++i) {
      std::cout << tree_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < rev_.size(); ++i) {
      std::cout << rev_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < swap_.size(); ++i) {
      std::cout << swap_.at(i) << ", ";
    }
    std::cout << std::endl;
    std::cout << "=================" << std::endl;
  }

  void Reverse(int k) {
    for (int t = rev_.size()-k; t < rev_.size(); ++t) {
      rev_[t] = !rev_[t];
    }
  }

  void Swap(int k) {
    if (k >= swap_.size()) return;
    swap_[swap_.size()-k-1] = !swap_[swap_.size()-k-1];
  }

  Int Sum(int l, int r) const {
    return Ssum_(l, r, 0, 0, n_-1);
  }

 private:
  Int Level_(int i) const { return static_cast<Int>(std::log2(1+i)); }
  Int Parent_(int i) const { return i <= 0 ? 0 : (i-1) / 2; }
  Int LChild_(int i) const {
    const int level = Level_(i);
    const bool x = rev_[level] != swap_[level];
    return 2*i+1+x;
  }
  Int RChild_(int i) const {
    const int level = Level_(i);
    const bool x = rev_[level] == swap_[level];
    return 2*i+1+x;
  }

  Int Ssum_(int l, int r, int i, int ll, int rr) const {
    if (l > r || ll > rr) return 0;
    if (!(ll <= l && r <= rr)) return 0;
    if (l == ll && r == rr) return tree_.at(i);
    const int m = (ll+rr)/2;
    // std::cout << "l=" << l << ", m=" << m << ", r=" << r << ", ll=" << ll << ", rr=" << rr << std::endl;
    return Ssum_(l, std::min(r, m), LChild_(i), ll, m) + Ssum_(std::max(l, m+1), r, RChild_(i), m+1, rr);
  }

  void BuildTree_(const vector<Int>& xs) {
    tree_.resize(2*xs.size()-1, kDirty);

    for (int i = 0; i < xs.size(); ++i) {
      tree_.at(tree_.size()-xs.size()+i) = xs.at(i);
    }

    Sum_(0);
  }

  Int Sum_(int i) {
    if (LChild_(i) >= tree_.size()) return tree_.at(i);
    tree_.at(i) = Sum_(LChild_(i)) + Sum_(RChild_(i));
    return tree_.at(i);
  }

 private:
  vector<Int> tree_;
  const int n_;
  vector<bool> rev_;
  vector<bool> swap_;
};

int mmain() {
  vector<Int> xs = {1, 2, 3, 4, 5, 6, 7, 8};
  SegmentTree st(xs);
  st.Print();
  // st.Replace(0, 10);
  // st.Replace(1, 10);
  // st.Replace(2, 10);
  // st.Replace(3, 10);
  // st.Replace(4, 10);
  // st.Replace(5, 10);
  // st.Replace(6, 10);
  st.Replace(7, 10);
  st.Print();
  std::cout << st.Sum(2, 4) << std::endl;
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(0);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(1);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(3);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(0);
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(1);

  return 0;
}

int main() {
  int n, q;
  std::cin >> n >> q;

  vector<Int> xs(1 << n);
  for (int i = 0; i < (1 << n); ++i) {
    std::cin >> xs[i];
  }
  SegmentTree st(xs);

  while (q --> 0) {
    int c;
    std::cin >> c;

    Int k;
    switch (c) {
      case 1:
        int x;
        std::cin >> x >> k;
        st.Replace(x-1, k);
        break;
      case 2:
        std::cin >> k;
        st.Reverse(k);
        break;
      case 3:
        std::cin >> k;
        st.Swap(k);
        break;
      case 4:
        int l, r;
        std::cin >> l >> r;
        std::cout << st.Sum(l-1, r-1) << std::endl;
        break;
      default:
        break;
    }
    // st.Print();
  }

  return 0;
}


#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <vector>

using std::vector;

typedef long long Int;

constexpr Int kDirty = 10000000000000000ll;

class SegmentTree {
 public:
  SegmentTree(const vector<Int>& xs) : n_(xs.size()) {
    const auto k = static_cast<int>(1 + std::log2(n_));
    rev_.resize(k, false);
    swap_.resize(k, false);

    BuildTree_(xs);
  }

  void Replace(const int x, Int value) {
    int n = n_;
    int xx = x;
    int i = 0;

    // Add value.
    do {
      const int m = n / 2;
      const auto left = xx <= m;
      i = left ? LChild_(i) : RChild_(i);
      if (!left) {
        xx -= m;
      }
      n -= m;
    } while (n > 1);
    // std::cout << i << ", " << tree_[i] << std::endl;
    tree_[i] = value;

    // Adjust tree.
    do {
      i = Parent_(i);
      // std::cout << i << ", " << LChild_(i) << ", " << RChild_(i) << std::endl;
      tree_[i] = tree_[LChild_(i)] + tree_[RChild_(i)];
    } while (i > 0);
  }

  void Print() const {
    std::cout << "=================" << std::endl;
    for (int i = 0; i < n_; ++i) {
      std::cout << Sum(i, i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < tree_.size(); ++i) {
      std::cout << tree_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < rev_.size(); ++i) {
      std::cout << rev_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < swap_.size(); ++i) {
      std::cout << swap_.at(i) << ", ";
    }
    std::cout << std::endl;
    std::cout << "=================" << std::endl;
  }

  void Reverse(int k) {
    for (int t = rev_.size()-k-1; t < rev_.size(); ++t) {
      rev_[t] = !rev_[t];
    }
  }

  void Swap(int k) {
    // if (k >= swap_.size()) return;
    swap_[swap_.size()-k-2] = !swap_[swap_.size()-k-2];
  }

  Int Sum(int l, int r) const {
    return Ssum_(l, r, 0, 0, n_-1);
  }

 private:
  Int Level_(int i) const { return static_cast<Int>(std::log2(1+i)); }
  Int Parent_(int i) const { return i <= 0 ? 0 : (i-1) / 2; }
  Int LChild_(int i) const {
    const int level = Level_(i);
    const bool x = rev_[level] != swap_[level];
    return 2*i+1+x;
  }
  Int RChild_(int i) const {
    const int level = Level_(i);
    const bool x = rev_[level] == swap_[level];
    return 2*i+1+x;
  }

  Int Ssum_(int l, int r, int i, int ll, int rr) const {
    if (l > r || ll > rr) return 0;
    if (!(ll <= l && r <= rr)) return 0;
    if (l == ll && r == rr) return tree_.at(i);
    const int m = (ll+rr)/2;
    // std::cout << "l=" << l << ", m=" << m << ", r=" << r << ", ll=" << ll << ", rr=" << rr << std::endl;
    return Ssum_(l, std::min(r, m), LChild_(i), ll, m) + Ssum_(std::max(l, m+1), r, RChild_(i), m+1, rr);
  }

  void BuildTree_(const vector<Int>& xs) {
    tree_.resize(2*xs.size()-1, kDirty);

    for (int i = 0; i < xs.size(); ++i) {
      tree_.at(tree_.size()-xs.size()+i) = xs.at(i);
    }

    Sum_(0);
  }

  Int Sum_(int i) {
    if (LChild_(i) >= tree_.size()) return tree_.at(i);
    tree_.at(i) = Sum_(LChild_(i)) + Sum_(RChild_(i));
    return tree_.at(i);
  }

 private:
  vector<Int> tree_;
  const int n_;
  vector<bool> rev_;
  vector<bool> swap_;
};

int mmain() {
  vector<Int> xs = {1};
  SegmentTree st(xs);
  st.Print();
  // st.Replace(0, 10);
  // st.Replace(1, 10);
  // st.Replace(2, 10);
  // st.Replace(3, 10);
  // st.Replace(4, 10);
  // st.Replace(5, 10);
  // st.Replace(6, 10);
  st.Replace(0, 10);
  st.Print();
  std::cout << st.Sum(0, 0) << std::endl;
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(0);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(1);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(3);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(0);
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(1);

  return 0;
}

int main() {
  int n, q;
  std::cin >> n >> q;

  vector<Int> xs(1 << n);
  for (int i = 0; i < (1 << n); ++i) {
    std::cin >> xs[i];
  }
  SegmentTree st(xs);

  while (q --> 0) {
    int c;
    std::cin >> c;

    Int k;
    switch (c) {
      case 1:
        int x;
        std::cin >> x >> k;
        st.Replace(x-1, k);
        break;
      case 2:
        std::cin >> k;
        st.Reverse(k);
        break;
      case 3:
        std::cin >> k;
        st.Swap(k);
        break;
      case 4:
        int l, r;
        std::cin >> l >> r;
        std::cout << st.Sum(l-1, r-1) << std::endl;
        break;
      default:
        break;
    }
    // st.Print();
  }

  return 0;
}


#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <vector>

using std::vector;

typedef long long Int;

constexpr Int kDirty = 10000000000000000ll;

class SegmentTree {
 public:
  SegmentTree(const vector<Int>& xs) : n_(xs.size()) {
    const auto k = static_cast<int>(1 + std::log2(n_));
    rev_.resize(k, false);
    swap_.resize(k, false);

    BuildTree_(xs);
  }

  void Replace(const int x, Int value) {
    int n = n_;
    int xx = x;
    int i = 0;

    // Add value.
    do {
      const int m = n / 2;
      const auto left = xx < m;
      i = left ? LChild_(i) : RChild_(i);
      if (!left) {
        xx -= m;
      }
      n -= m;
    } while (n > 1);
    // std::cout << i << ", " << tree_[i] << std::endl;
    tree_[i] = value;

    // Adjust tree.
    do {
      i = Parent_(i);
      // std::cout << i << ", " << LChild_(i) << ", " << RChild_(i) << std::endl;
      tree_[i] = tree_[LChild_(i)] + tree_[RChild_(i)];
    } while (i > 0);
  }

  void Print() const {
    std::cout << "=================" << std::endl;
    for (int i = 0; i < n_; ++i) {
      std::cout << Sum(i, i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < tree_.size(); ++i) {
      std::cout << tree_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < rev_.size(); ++i) {
      std::cout << rev_.at(i) << ", ";
    }
    std::cout << std::endl;
    for (int i = 0; i < swap_.size(); ++i) {
      std::cout << swap_.at(i) << ", ";
    }
    std::cout << std::endl;
    std::cout << "=================" << std::endl;
  }

  void Reverse(int k) {
    for (int t = rev_.size()-k-1; t < rev_.size(); ++t) {
      rev_[t] = !rev_[t];
    }
  }

  void Swap(int k) {
    // if (k >= swap_.size()) return;
    swap_[swap_.size()-k-2] = !swap_[swap_.size()-k-2];
  }

  Int Sum(int l, int r) const {
    return Ssum_(l, r, 0, 0, n_-1);
  }

 private:
  Int Level_(int i) const { return static_cast<Int>(std::log2(1+i)); }
  Int Parent_(int i) const { return i <= 0 ? 0 : (i-1) / 2; }
  Int LChild_(int i) const {
    const int level = Level_(i);
    const bool x = rev_[level] != swap_[level];
    return 2*i+1+x;
  }
  Int RChild_(int i) const {
    const int level = Level_(i);
    const bool x = rev_[level] == swap_[level];
    return 2*i+1+x;
  }

  Int Ssum_(int l, int r, int i, int ll, int rr) const {
    if (l > r || ll > rr) return 0;
    if (!(ll <= l && r <= rr)) return 0;
    if (l == ll && r == rr) return tree_.at(i);
    const int m = (ll+rr)/2;
    // std::cout << "l=" << l << ", m=" << m << ", r=" << r << ", ll=" << ll << ", rr=" << rr << std::endl;
    return Ssum_(l, std::min(r, m), LChild_(i), ll, m) + Ssum_(std::max(l, m+1), r, RChild_(i), m+1, rr);
  }

  void BuildTree_(const vector<Int>& xs) {
    tree_.resize(2*xs.size()-1, kDirty);

    for (int i = 0; i < xs.size(); ++i) {
      tree_.at(tree_.size()-xs.size()+i) = xs.at(i);
    }

    Sum_(0);
  }

  Int Sum_(int i) {
    if (LChild_(i) >= tree_.size()) return tree_.at(i);
    tree_.at(i) = Sum_(LChild_(i)) + Sum_(RChild_(i));
    return tree_.at(i);
  }

 private:
  vector<Int> tree_;
  const int n_;
  vector<bool> rev_;
  vector<bool> swap_;
};

int mmain() {
  vector<Int> xs = {1};
  SegmentTree st(xs);
  st.Print();
  // st.Replace(0, 10);
  // st.Replace(1, 10);
  // st.Replace(2, 10);
  // st.Replace(3, 10);
  // st.Replace(4, 10);
  // st.Replace(5, 10);
  // st.Replace(6, 10);
  st.Replace(0, 10);
  st.Print();
  std::cout << st.Sum(0, 0) << std::endl;
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(0);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(1);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // st.Reverse(3);
  // st.Print();
  // std::cout << st.Sum(1, 2) << std::endl;
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(0);
  // std::cout << st.Sum(5, 6) << std::endl;
  // st.Swap(1);

  return 0;
}

int main() {
  int n, q;
  std::cin >> n >> q;

  vector<Int> xs(1 << n);
  for (int i = 0; i < (1 << n); ++i) {
    std::cin >> xs[i];
  }
  SegmentTree st(xs);

  while (q --> 0) {
    int c;
    std::cin >> c;

    Int k;
    switch (c) {
      case 1:
        int x;
        std::cin >> x >> k;
        st.Replace(x-1, k);
        break;
      case 2:
        std::cin >> k;
        st.Reverse(k);
        break;
      case 3:
        std::cin >> k;
        st.Swap(k);
        break;
      case 4:
        int l, r;
        std::cin >> l >> r;
        std::cout << st.Sum(l-1, r-1) << std::endl;
        break;
      default:
        break;
    }
    // st.Print();
  }

  return 0;
}