#include <bits/stdc++.h>
using namespace std;
long long N, M, X;
template <typename T, typename F>
struct SEGMENT_TREE {
  long long Li, Ri;
  long long pt = 0;
  vector<T> ST;
  vector<long long> L;
  vector<long long> R;
  vector<bool> lazy;
  T query_res, query_temp;
  bool query_flag;
  void new_node() {}
  SEGMENT_TREE(long long a, long long b) {
    ST.resize(3e5);
    L.resize(3e5);
    R.resize(3e5);
    lazy.resize(3e5);
    assert(a <= b);
    Li = a, Ri = b;
    new_node();
  }
  void build(vector<T> &vect) {
    assert(Ri - Li + 1 == (long long)vect.size());
    ST_build(0, Li, Ri, vect);
  }
  void insert(long long x, T nod) { ST_insert(0, Li, Ri, x, nod); }
  void update(long long x, F &up) { ST_update(0, Li, Ri, x, x, up); }
  void update(long long a, long long b, F &up) {
    ST_update(0, Li, Ri, a, b, up);
  }
  T query(long long x) {
    query_res = T{};
    query_flag = false;
    ST_query(0, Li, Ri, x, x);
    return query_res;
  }
  T query(long long a, long long b) {
    query_res = T{};
    query_flag = false;
    ST_query(0, Li, Ri, a, b);
    return query_res;
  }
  void ST_build(long long node, long long l, long long r, vector<T> &vect) {
    if (l == r) {
      ST[node] = vect[l - Li];
      return;
    } else {
      L[node] = ++pt;
      new_node();
      R[node] = ++pt;
      new_node();
    }
    long long mid = (l + r) / 2;
    ST_build(L[node], l, mid, vect);
    ST_build(R[node], mid + 1, r, vect);
    ST[node].merge(ST[L[node]], ST[R[node]]);
  }
  void ST_insert(long long node, long long l, long long r, long long x,
                 T &nod) {
    if (l != r) {
      if (L[node] == 0) {
        L[node] = ++pt;
        new_node();
      }
      if (R[node] == 0) {
        R[node] = ++pt;
        new_node();
      }
    }
    if (lazy[node]) {
      if (l != r) {
        ST[node].propagation(ST[L[node]], ST[R[node]]);
        lazy[L[node]] = true;
        lazy[R[node]] = true;
      }
      ST[node].update(l, r);
      lazy[node] = false;
    }
    if (l == r) {
      ST[node] = nod;
      return;
    }
    long long mid = (l + r) / 2;
    if (x <= mid)
      ST_insert(L[node], l, mid, x, nod);
    else
      ST_insert(R[node], mid + 1, r, x, nod);
    ST[node].merge(ST[L[node]], ST[R[node]]);
  }
  void ST_update(long long node, long long l, long long r, long long a,
                 long long b, F &up) {
    if (l != r) {
      if (L[node] == 0) {
        L[node] = ++pt;
        new_node();
      }
      if (R[node] == 0) {
        R[node] = ++pt;
        new_node();
      }
    }
    if (lazy[node]) {
      if (l != r) {
        ST[node].propagation(ST[L[node]], ST[R[node]]);
        lazy[L[node]] = true;
        lazy[R[node]] = true;
      }
      ST[node].update(l, r);
      lazy[node] = false;
    }
    if (r < a || l > b) return;
    if (a <= l && r <= b) {
      ST[node].push(up);
      if (l != r) {
        ST[node].propagation(ST[L[node]], ST[R[node]]);
        lazy[L[node]] = true;
        lazy[R[node]] = true;
      }
      ST[node].update(l, r);
      return;
    }
    long long mid = (l + r) / 2;
    ST_update(L[node], l, mid, a, b, up);
    ST_update(R[node], mid + 1, r, a, b, up);
    ST[node].merge(ST[L[node]], ST[R[node]]);
  }
  void ST_query(long long node, long long l, long long r, long long a,
                long long b) {
    if (l != r) {
      if (L[node] == 0) {
        L[node] = ++pt;
        new_node();
      }
      if (R[node] == 0) {
        R[node] = ++pt;
        new_node();
      }
    }
    if (lazy[node]) {
      if (l != r) {
        ST[node].propagation(ST[L[node]], ST[R[node]]);
        lazy[L[node]] = true;
        lazy[R[node]] = true;
      }
      ST[node].update(l, r);
      lazy[node] = false;
    }
    if (a <= l && r <= b) {
      if (query_flag) {
        query_temp = T{};
        query_temp.merge(query_res, ST[node]);
        query_res = query_temp;
      } else {
        query_res = ST[node];
        query_flag = true;
      }
      return;
    }
    long long mid = (l + r) / 2;
    if (a <= mid) ST_query(L[node], l, mid, a, b);
    if (b > mid) ST_query(R[node], mid + 1, r, a, b);
  }
};
struct QUERY {
  long long sum = 0;
};
struct NODE {
  long long sum = 0;
  long long tam = 0;
  vector<pair<long long, long long>> va, vb;
  void merge(NODE &H1, NODE &H2) {
    sum = H1.sum + H2.sum;
    tam = H1.tam + H2.tam;
    long long pt = 0;
    for (long long i = H2.va.size() - 1; i >= 0; i--) {
      while (pt < H1.vb.size() && (H1.vb[pt].first | H2.va[i].first) < X) {
        pt++;
      }
      if (pt < H1.vb.size()) {
        long long val = 0;
        if (i == H2.va.size() - 1)
          val = H2.tam - H2.va[i].second;
        else
          val = H2.va[i + 1].second - H2.va[i].second;
        sum += val * (H1.tam - H1.vb[pt].second);
      }
    }
    va = H1.va;
    long long temp = va.back().first;
    for (auto x : H2.va) {
      if (temp != (temp | x.first)) {
        temp = (temp | x.first);
        va.push_back({temp, x.second + H1.tam});
      }
    }
    vb = H2.vb;
    temp = vb.back().first;
    for (auto x : H1.vb) {
      if (temp != (temp | x.first)) {
        temp = (temp | x.first);
        vb.push_back({temp, x.second + H2.tam});
      }
    }
  }
  void push(QUERY &Q) {}
  void update(long long l, long long r) {}
  void propagation(NODE &H1, NODE &H2) {}
};
int32_t main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cin >> N >> M >> X;
  SEGMENT_TREE<NODE, QUERY> ST(1, N);
  vector<NODE> vvv;
  for (long long i = 1; i <= N; i++) {
    long long n;
    cin >> n;
    NODE tp;
    if (n >= X) tp.sum = 1;
    tp.tam = 1;
    tp.va.push_back({n, 0});
    tp.vb.push_back({n, 0});
    vvv.push_back(tp);
  }
  ST.build(vvv);
  for (long long i = 1; i <= M; i++) {
    long long qu;
    cin >> qu;
    if (qu == 1) {
      long long x, v;
      cin >> x >> v;
      NODE tp;
      if (v >= X) tp.sum = 1;
      tp.tam = 1;
      tp.va.push_back({v, 0});
      tp.vb.push_back({v, 0});
      ST.insert(x, tp);
    } else {
      long long a, b;
      cin >> a >> b;
      cout << ST.query(a, b).sum << '\n';
    }
  }
  return 0;
}
