#include <bits/stdc++.h>
using namespace std;
struct node {
  int q[65];
  int cnt;
} tree[810000];
int tree1[810000];
int a[210000], b[210000];
int n, q;
int t1, t2, t3, t4;
node gas(node &x) {
  bool used[65];
  memset(used, 0, sizeof(used));
  for (int i = 0; i <= 30; i++) {
    int w = 0;
    for (int j = 1; j <= x.cnt; j++)
      if (!used[j] && x.q[j] & (1 << i)) {
        w = j;
        break;
      }
    if (w) {
      for (int j = 1; j <= x.cnt; j++)
        if (j != w && x.q[j] & (1 << i)) {
          x.q[j] ^= x.q[w];
        }
      used[w] = 1;
    }
  }
  node ans;
  memset(&ans, 0, sizeof(ans));
  for (int i = 1; i <= x.cnt; i++) {
    if (x.q[i]) ans.q[++ans.cnt] = x.q[i];
  }
  return ans;
}
node cal(node &x, node &y) {
  node ans;
  memset(&ans, 0, sizeof(ans));
  for (int i = 1; i <= x.cnt; i++) {
    ans.q[++ans.cnt] = x.q[i];
  }
  for (int i = 1; i <= y.cnt; i++) {
    ans.q[++ans.cnt] = y.q[i];
  }
  return gas(ans);
}
void build(int l, int r, int now) {
  if (l == r) {
    tree[now].cnt = 1;
    tree[now].q[1] = b[l];
    return;
  }
  int mid = (l + r) >> 1;
  build(l, mid, now * 2);
  build(mid + 1, r, now * 2 + 1);
  tree[now] = cal(tree[now * 2], tree[now * 2 + 1]);
}
void insert(int l, int r, int now, int pos, int val) {
  if (l == r) {
    tree[now].q[1] ^= val;
    b[l] ^= val;
    return;
  }
  int mid = (l + r) >> 1;
  if (pos <= mid)
    insert(l, mid, now * 2, pos, val);
  else
    insert(mid + 1, r, now * 2 + 1, pos, val);
  tree[now] = cal(tree[now * 2], tree[now * 2 + 1]);
}
void insert1(int l, int r, int now, int lq, int rq, int val) {
  if (lq <= l && r <= rq) {
    if (l != r)
      tree1[now] ^= val;
    else
      a[l] ^= val;
    return;
  }
  int mid = (l + r) >> 1;
  if (mid >= lq) insert1(l, mid, now * 2, lq, rq, val);
  if (mid < rq) insert1(mid + 1, r, now * 2 + 1, lq, rq, val);
}
node query(int l, int r, int now, int lq, int rq) {
  if (lq <= l && r <= rq) {
    return tree[now];
  }
  int mid = (l + r) >> 1;
  node a1, a2;
  memset(&a1, 0, sizeof(a1));
  memset(&a2, 0, sizeof(a2));
  if (mid >= lq) a1 = query(l, mid, now * 2, lq, rq);
  if (mid < rq) a2 = query(mid + 1, r, now * 2 + 1, lq, rq);
  return cal(a1, a2);
}
void pushdown(int now, int l, int r) {
  if (tree1[now]) {
    int mid = (l + r) >> 1;
    if (mid != l)
      tree1[now * 2] ^= tree1[now];
    else
      a[l] ^= tree1[now];
    if (mid + 1 != r)
      tree1[now * 2 + 1] ^= tree1[now];
    else
      a[r] ^= tree1[now];
  }
  tree1[now] = 0;
}
void query1(int l, int r, int now, int pos) {
  if (l == r) return;
  int mid = (l + r) >> 1;
  pushdown(now, l, r);
  if (pos <= mid)
    query1(l, mid, now * 2, pos);
  else
    query1(mid + 1, r, now * 2 + 1, pos);
}
int main() {
  scanf("%d%d", &n, &q);
  for (int i = 1; i <= n; i++) {
    scanf("%d", &a[i]);
  }
  b[1] = a[1];
  for (int i = 2; i <= n; i++) {
    b[i] = a[i - 1] ^ a[i];
  }
  build(1, n, 1);
  for (int i = 1; i <= q; i++) {
    scanf("%d", &t1);
    if (t1 == 1) {
      scanf("%d%d%d", &t2, &t3, &t4);
      insert(1, n, 1, t2, t4);
      if (t3 != n) insert(1, n, 1, t3 + 1, t4);
      insert1(1, n, 1, t2, t3, t4);
    } else {
      scanf("%d%d", &t2, &t3);
      node a1, a2;
      memset(&a1, 0, sizeof(a1));
      if (t2 != t3) a1 = query(1, n, 1, t2 + 1, t3);
      query1(1, n, 1, t2);
      a2.cnt = 1;
      a2.q[1] = a[t2];
      a1 = cal(a1, a2);
      printf("%d\n", 1 << a1.cnt);
    }
  }
  return 0;
}
