#include <iostream>
#include <vector>
using namespace std;
const int MOD = 1000000007;
// Segment Tree for range OR queries.
struct SegTree {
int n;
vector<int> tree;
SegTree(const vector<int>& arr) {
n = arr.size();
tree.resize(4*n);
build(arr, 0, n-1, 1);
}
void build(const vector<int>& arr, int l, int r, int idx) {
if(l == r) {
tree[idx] = arr[l];
return;
}
int mid = (l + r) / 2;
build(arr, l, mid, idx*2);
build(arr, mid+1, r, idx*2+1);
tree[idx] = tree[idx*2] | tree[idx*2+1];
}
// update position pos (0-indexed) with new value (here using XOR update, so new value = old XOR x)
void update(int pos, int val, int l, int r, int idx) {
if(l == r) {
tree[idx] = val;
return;
}
int mid = (l + r) / 2;
if(pos <= mid)
update(pos, val, l, mid, idx*2);
else
update(pos, val, mid+1, r, idx*2+1);
tree[idx] = tree[idx*2] | tree[idx*2+1];
}
int query(int ql, int qr, int l, int r, int idx) {
if(ql > r || qr < l) return 0;
if(ql <= l && r <= qr) return tree[idx];
int mid = (l + r) / 2;
int leftOr = query(ql, qr, l, mid, idx*2);
int rightOr = query(ql, qr, mid+1, r, idx*2+1);
return leftOr | rightOr;
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N, Q;
cin >> N >> Q;
vector<int> A(N);
for (int i = 0; i < N; i++){
cin >> A[i];
}
// Build segment tree for OR queries.
SegTree seg(A);
// Precompute powers of 2 up to N.
vector<long long> pow2(N+1);
pow2[0] = 1;
for (int i = 1; i <= N; i++){
pow2[i] = (pow2[i-1] * 2LL) % MOD;
}
// Process queries.
while(Q--){
int type;
cin >> type;
if(type == 1) {
int pos, x;
cin >> pos >> x;
pos--; // convert to 0-indexed
// update A[pos] = A[pos] XOR x
A[pos] ^= x;
seg.update(pos, A[pos], 0, N-1, 1);
} else if(type == 2) {
int l, r;
cin >> l >> r;
l--; r--; // convert to 0-indexed
int rangeOr = seg.query(l, r, 0, N-1, 1);
int len = r - l + 1;
long long ans = (1LL * rangeOr * pow2[len-1]) % MOD;
cout << ans << "\n";
}
}
return 0;
}