#include <bits/stdc++.h>
using std::vector;
const int MAXN = 1e5 + 20, MAXSeg = 1 << 18;
int X;
int N = 1;
struct chunk {
  int val, len;
  chunk() {}
  chunk(const int &VAL, const int &LEN) : val(VAL), len(LEN) {}
};
struct interval {
  long long ctrb;
  vector<chunk> pre, suf;
  interval() {}
  interval(const int &VAL) {
    ctrb = (VAL >= X);
    pre.push_back(chunk(VAL, 1));
    suf.push_back(chunk(VAL, 1));
  }
  interval(const interval &A, const interval &B) {
    ctrb = A.ctrb + B.ctrb;
    int Sum = 0;
    for (int i = 0, j = (int)B.pre.size() - 1; i < (int)A.suf.size(); ++i) {
      while (j >= 0 && (A.suf[i].val | B.pre[j].val) >= X)
        Sum += B.pre[j].len, --j;
      ctrb += 1ll * A.suf[i].len * Sum;
    }
    pre.assign(A.pre.begin(), A.pre.end());
    for (int i = 0; i < (int)B.pre.size(); ++i) {
      if (pre.empty())
        pre.push_back(chunk(B.pre[i].val, B.pre[i].len));
      else if ((pre[(int)pre.size() - 1].val | B.pre[i].val) !=
               pre[(int)pre.size() - 1].val)
        pre.push_back(
            chunk((pre[(int)pre.size() - 1].val | B.pre[i].val), B.pre[i].len));
      else
        pre[(int)pre.size() - 1].len += B.pre[i].len;
    }
    suf.assign(B.suf.begin(), B.suf.end());
    for (int i = 0; i < (int)A.suf.size(); ++i) {
      if (suf.empty())
        suf.push_back(chunk(A.suf[i].val, A.suf[i].len));
      else if ((suf[(int)suf.size() - 1].val | A.suf[i].val) !=
               suf[(int)suf.size() - 1].val)
        suf.push_back(
            chunk((suf[(int)suf.size() - 1].val | A.suf[i].val), A.suf[i].len));
      else
        suf[(int)suf.size() - 1].len += A.suf[i].len;
    }
  }
} node[MAXSeg];
inline void pushup(const int &x) {
  node[x] = interval(node[x << 1], node[(x << 1) | 1]);
}
void modify(const int &pos, const int &val, const int &nl = 1,
            const int &nr = N, const int &x = 1) {
  if (nl == nr) {
    node[x] = interval(val);
    return;
  }
  int mid = (nl + nr) >> 1;
  if (pos <= mid)
    modify(pos, val, nl, mid, x << 1);
  else
    modify(pos, val, mid + 1, nr, (x << 1) | 1);
  pushup(x);
}
interval query(const int &l, const int &r, const int &nl = 1, const int &nr = N,
               const int &x = 1) {
  if (nl == l && nr == r) return node[x];
  int mid = (nl + nr) >> 1;
  if (r <= mid)
    return query(l, r, nl, mid, x << 1);
  else if (l >= mid + 1)
    return query(l, r, mid + 1, nr, (x << 1) | 1);
  else
    return interval(query(l, mid, nl, mid, x << 1),
                    query(mid + 1, r, mid + 1, nr, (x << 1) | 1));
}
inline int read() {
  int x = 0;
  char c = getchar();
  while (c < '0' || c > '9') c = getchar();
  while (c >= '0' && c <= '9')
    x = (x << 3) + (x << 1) + (48 ^ c), c = getchar();
  return x;
}
void write(const long long &x) {
  if (x / 10) write(x / 10);
  putchar('0' + x % 10);
}
int main() {
  int n = read(), m = read();
  X = read();
  while (N < n) N <<= 1;
  for (int i = N; i < N + n; ++i) node[i] = interval(read());
  for (int i = N - 1; i >= 1; --i) pushup(i);
  for (int t = 0; t < m; ++t) {
    int op = read();
    if (op == 1) {
      int i = read(), y = read();
      modify(i, y);
    } else {
      int l = read(), r = read();
      write(query(l, r).ctrb);
      putchar('\n');
    }
  }
}
