3 5
2 1 608591421 720962564
3 2 608591421 641991574
3 2 718110706 353409763
2 3 482786015 858341723
3 2 825397574 357507279
 2 1
2 1 317425595 636156322
 50000 1
20845 28516 904146168 997637433

Yes
641991574 1
2 
 Yes
0 0

 Yes
0 0


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        TaskE solver = new TaskE();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskE {
        final int maxSize = 31;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int n = in.nextInt(), q = in.nextInt();

            int[] values = new int[n];
            for (int i = 0; i < n; ++i)
                values[i] = in.nextInt();

            SegmentTree t = new SegmentTree(values);
            while (q-- > 0) {
                int type = in.nextInt();
                if (type == 1) {
                    int left = in.nextInt() - 1, right = in.nextInt() - 1, value = in.nextInt();
                    t.update(left, right, value);
                } else {
                    int left = in.nextInt() - 1, right = in.nextInt() - 1;
                    DArray result = t.query(left, right);
                    int ans = 0;
                    for (int p : result.a) if (p != 0) ans++;

                    out.println(1 << ans);
                }
            }
        }

        private int merge(int[] a, int sa, int[] b, int sb, int[] dest) {
            int[] result = new int[sa + sb];
            int sr = 0, i = 0, j = 0;
            while (i < sa || j < sb) {
                if (j == sb || (i < sa && a[i] >= b[j])) result[sr++] = a[i++];
                else result[sr++] = b[j++];
            }
            for (i = 0; i < sr; ++i) {
                if (result[i] == 0) break;
                int p = biggestOneBit(result[i]);
                for (j = i + 1; j < sr; ++j) {
                    if ((result[j] & (1 << p)) != 0) result[j] ^= result[i];
                    //else break;
                }
            }
            sr = Math.min(sr, maxSize);
            System.arraycopy(result, 0, dest, 0, sr);
            return sr;
        }

        private int biggestOneBit(int x) {
            return 31 - Integer.numberOfLeadingZeros(x);
        }

        private class SegmentTree {
            private int[][] tree;
            private int[] treeSize;
            private int[] lazy;
            int size;

            public SegmentTree(int[] values) {
                this.size = values.length;
                tree = new int[4 * size + 5][maxSize];
                treeSize = new int[4 * size + 5];
                lazy = new int[4 * size + 5];
                build(0, 0, size - 1, values);
            }

            private void updateNode(int node) {
                treeSize[node] = merge(tree[2 * node + 1], treeSize[2 * node + 1],
                        tree[2 * node + 2], treeSize[2 * node + 2],
                        tree[node]);
            }

            private void doXor(int[] a, int value) {
                for (int i = 0; i < size; ++i)
                    a[i] ^= value;
            }

            private void build(int node, int left, int right, int[] values) {
                if (left == right) {
                    tree[node][0] = values[left];
                    treeSize[node] = 1;
                } else {
                    int mid = (left + right) / 2;
                    build(2 * node + 1, left, mid, values);
                    build(2 * node + 2, mid + 1, right, values);
                    updateNode(node);
                }
            }

            private void split(int node, int left, int right) {
                if (lazy[node] != 0) {
                /*for (int i = 0; i < treeSize[node]; ++i)
                    tree[node][i] ^= lazy[node];
                Arrays.sort(tree[node], 0, treeSize[node]);
                ArraysUtils.reverse(tree[node], 0, treeSize[node]);
                for (int i = 0; i < treeSize[node]; ++i) {
                    int p = biggestOneBit(tree[node][i]);
                    for (int j = i + 1; j < treeSize[node]; ++j) {
                        if ((tree[node][j] & (1 << p)) != 0) tree[node][j] ^= tree[node][i];
                        //else break;
                    }
                }*/

                    if (left < right) {
                        split(2 * node + 1, left, (left + right) / 2);
                        split(2 * node + 2, (left + right) / 2 + 1, right);

                        doXor(tree[2 * node + 1], lazy[node]);
                        doXor(tree[2 * node + 2], lazy[node]);

                        updateNode(node);

                        doXor(tree[2 * node + 1], lazy[node]);
                        doXor(tree[2 * node + 2], lazy[node]);

                        lazy[2 * node + 1] ^= lazy[node];
                        lazy[2 * node + 2] ^= lazy[node];
                    } else {
                        tree[node][0] ^= lazy[node];
                    }

                    lazy[node] = 0;
                }
            }

            private void cupdate(int node, int left, int right, int lq, int rq, int value) {
                split(node, left, right);
                if (lq <= left && right <= rq) {
                    lazy[node] ^= value;
                } else {
                    int mid = (left + right) / 2;

                    if (lq <= mid) cupdate(2 * node + 1, left, mid, lq, rq, value);
                    if (rq > mid) cupdate(2 * node + 2, mid + 1, right, lq, rq, value);
                    split(2 * node + 1, left, mid);
                    split(2 * node + 2, mid + 1, right);
                    updateNode(node);
                }
            }

            private void cquery(int node, int left, int right, int lq, int rq, DArray dest) {
                split(node, left, right);
                if (lq <= left && right <= rq) {
                    dest.cnt = merge(dest.a.clone(), dest.cnt, tree[node], treeSize[node], dest.a);
                } else {
                    int mid = (left + right) / 2;
                    if (lq <= mid) cquery(2 * node + 1, left, mid, lq, rq, dest);
                    if (rq > mid) cquery(2 * node + 2, mid + 1, right, lq, rq, dest);
                }
            }

            public void update(int left, int right, int value) {
                cupdate(0, 0, size - 1, left, right, value);
            }

            public DArray query(int left, int right) {
                DArray result = new DArray();
                cquery(0, 0, size - 1, left, right, result);
                return result;
            }

        }

        private class DArray {
            int[] a;
            int cnt;

            DArray() {
                a = new int[maxSize];
                cnt = 0;
            }

        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;

        public InputReader(InputStream stream) {
            this.stream = stream;
        }

        public int read() {
            if (numChars == -1)
                throw new UnknownError();
            if (curChar >= numChars) {
                curChar = 0;
                try {
                    numChars = stream.read(buf);
                } catch (IOException e) {
                    throw new UnknownError();
                }
                if (numChars <= 0)
                    return -1;
            }
            return buf[curChar++];
        }

        public int nextInt() {
            return Integer.parseInt(next());
        }

        public String next() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            StringBuffer res = new StringBuffer();
            do {
                res.appendCodePoint(c);
                c = read();
            } while (!isSpaceChar(c));

            return res.toString();
        }

        private boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

    }
}

