#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 2;
const int M = 32;
const long long INF = 1e16;
const long long mod = 998244353;
const double PI = acos(-1.0);
const double esp = 1e-7;
const int MAXN = 2e5 + 5;
long long tree[N * 4][M + 1], ans[M + 1], a[N], bit[N], b[N];
int n, m;
inline int lowbit(int x) { return x & (-x); }
void add(int x, long long v) {
  if (x == 0) return;
  while (x <= n) {
    bit[x] ^= v;
    x += lowbit(x);
  }
}
long long getxor(int x) {
  long long sum = 0;
  while (x) {
    sum ^= bit[x];
    x -= lowbit(x);
  }
  return sum;
}
inline void insert(int root, long long x) {
  for (int i = M; i >= 0; i--) {
    if (x & (1ll << i)) {
      if (tree[root][i] == 0) {
        tree[root][i] = x;
        break;
      } else
        x ^= tree[root][i];
    }
  }
}
inline void pushup(int root) {
  for (int i = 0; i <= M; i++) tree[root][i] = tree[root << 1 | 1][i];
  for (int i = M; i >= 0; i--) {
    long long x = tree[root << 1][i];
    if (x == 0) continue;
    for (int j = M; j >= 0; j--) {
      if (x & (1ll << j)) {
        if (tree[root][j] == 0) {
          tree[root][j] = x;
          break;
        } else
          x ^= tree[root][j];
      }
    }
  }
}
void build(int root, int left, int right) {
  memset(tree[root], 0, sizeof(tree[root]));
  if (left == right) {
    insert(root, b[left]);
    return;
  }
  int mid = (left + right) >> 1;
  build(root << 1, left, mid);
  build(root << 1 | 1, mid + 1, right);
  pushup(root);
}
void update(int root, int left, int right, int idx, long long v) {
  if (left > idx || right < idx) return;
  if (left == right) {
    if (left == idx) {
      b[left] ^= v;
      memset(tree[root], 0, sizeof(tree[root]));
      insert(root, b[left]);
    }
    return;
  }
  int mid = (left + right) >> 1;
  if (idx <= mid)
    update(root << 1, left, mid, idx, v);
  else
    update(root << 1 | 1, mid + 1, right, idx, v);
  pushup(root);
}
inline void getans(int root) {
  for (int i = M; i >= 0; i--) {
    long long x = tree[root][i];
    if (x == 0) continue;
    for (int j = M; j >= 0; j--) {
      if (x & (1ll << j)) {
        if (ans[j] == 0) {
          ans[j] = x;
          break;
        } else
          x ^= ans[j];
      }
    }
  }
}
void query(int root, int left, int right, int qleft, int qright) {
  if (left > qright || right < qleft) return;
  if (left >= qleft && right <= qright) {
    getans(root);
    return;
  }
  int mid = (left + right) >> 1;
  query(root << 1, left, mid, qleft, qright);
  query(root << 1 | 1, mid + 1, right, qleft, qright);
}
int main() {
  int op, l, r;
  long long v;
  scanf("%d%d", &n, &m);
  memset(bit, 0, sizeof(bit));
  a[0] = 0;
  for (int i = 1; i <= n; i++) {
    scanf("%I64d", &a[i]);
    add(i, a[i]);
    add(i + 1, a[i]);
  }
  for (int i = n; i >= 1; i--) b[i] = a[i] ^ a[i - 1];
  build(1, 1, n);
  while (m--) {
    scanf("%d%d%d", &op, &l, &r);
    if (op == 1) {
      scanf("%I64d", &v);
      add(l, v);
      add(r + 1, v);
      update(1, 1, n, l, v);
      if (r + 1 <= n) update(1, 1, n, r + 1, v);
    } else if (op == 2) {
      long long tmp = getxor(l);
      memset(ans, 0, sizeof(ans));
      if (l + 1 <= r) query(1, 1, n, l + 1, r);
      for (int i = M; i >= 0; i--) {
        if (tmp & (1ll << i)) {
          if (ans[i] == 0) {
            ans[i] = tmp;
            break;
          } else
            tmp ^= ans[i];
        }
      }
      long long sum = 1;
      for (int i = M; i >= 0; i--) {
        if (ans[i]) sum *= 2;
      }
      printf("%I64d\n", sum);
    }
  }
  return 0;
}
