#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pll = pair<long long, long long>;
constexpr char ln = '\n';
template <typename T, int B>
struct BinaryTrie {
  struct Node {
    int cnt;
    Node *p, *l, *r;
    Node(Node* p) : cnt(0), p(p), l(nullptr), r(nullptr) {}
  };
  T acc;
  Node* root;
  BinaryTrie() : acc(0), root(emplace(nullptr)) {}
  int size() { return count(root); }
  inline void update(const T b) { acc ^= b; }
  inline Node* emplace(Node* p) { return new Node(p); }
  inline int count(Node* a) const { return a ? a->cnt : 0; }
  T val(Node* a) {
    if (!a) return -1;
    T ret = 0;
    for (int i = 0; i < B; ++i) {
      assert(a->p);
      ret |= (T(a == a->p->r) << i);
      a = a->p;
    }
    return ret ^ acc;
  }
  Node* clear(Node* a) {
    if (!a || count(a)) return a;
    delete (a);
    return nullptr;
  }
  void insert(const T b, int k = 1) {
    const T nb = b ^ acc;
    Node* a = root;
    for (int i = B - 1; i >= 0; i--) {
      bool f = (nb >> i) & 1;
      if (!f && !a->l) a->l = emplace(a);
      if (f && !a->r) a->r = emplace(a);
      a = f ? a->r : a->l;
    }
    a->cnt += k;
    while ((a = a->p)) a->cnt = count(a->l) + count(a->r);
  }
  void erase(Node* a, int k = 1) {
    assert(a && a->cnt >= k);
    a->cnt -= k;
    while ((a = a->p)) {
      a->l = clear(a->l);
      a->r = clear(a->r);
      a->cnt = count(a->l) + count(a->r);
    }
  }
  void erase(T x) {
    auto a = find(x);
    erase(a);
  }
  Node* find(const T b) {
    const T nb = b ^ acc;
    Node* a = root;
    for (int i = B - 1; i >= 0; --i) {
      bool f = (nb >> i) & 1;
      a = f ? a->r : a->l;
      if (!a) return a;
    }
    return a;
  }
  Node* lower_bound(const T b) {
    if (!size()) return nullptr;
    const T nb = b ^ acc;
    Node* a = root;
    for (int i = B - 1; i >= 0; --i) {
      bool f = (nb >> i) & 1;
      if (!f && a->l) {
        a = a->l;
        continue;
      }
      if (f && a->r) {
        a = a->r;
        continue;
      }
      if ((b >> i) & 1) return next(a, i);
      return get(a, i);
    }
    return a;
  }
  Node* upper_bound(const T b) { return lower_bound(b + 1); }
  int lower_bound_order(const T b) {
    if (!size()) return size();
    const T nb = b ^ acc;
    Node* a = root;
    int ret = 0;
    for (int i = B - 1; i >= 0; --i) {
      bool f = (nb >> i) & 1;
      if (!f && a->l) {
        if ((b >> i) & 1) ret += count(a->r);
        a = a->l;
        continue;
      }
      if (f && a->r) {
        if ((b >> i) & 1) ret += count(a->l);
        a = a->r;
        continue;
      }
      if ((b >> i) & 1) return ret + count(a);
      return ret;
    }
    return ret;
  }
  int upper_bound_order(const T b) { return lower_bound_order(b + 1); }
  Node* max_element(const T b = 0) {
    assert(count(root));
    const T nb = b ^ acc;
    Node* a = root;
    for (int i = B - 1; i >= 0; --i) {
      bool f = (nb >> i) & 1;
      if (!a->l || !a->r)
        a = a->l ? a->l : a->r;
      else
        a = f ? a->l : a->r;
    }
    return a;
  }
  Node* min_element(const T b = 0) {
    return max_element(~b & ((T(1) << B) - 1));
  }
  Node* get(Node* a, int i) {
    if (!a) return a;
    Node *l = a->l, *r = a->r;
    if ((acc >> i) & 1) swap(l, r);
    if (l || r) return get(l ? l : r, i - 1);
    return a;
  }
  Node* next(Node* a, int i) {
    if (!(a->p)) return nullptr;
    Node *l = a->p->l, *r = a->p->r;
    if ((acc >> (i + 1)) & 1) swap(l, r);
    if (a == l && r) return get(r, i);
    return next(a->p, i + 1);
  }
  Node* find_by_order(int k) {
    Node* a = root;
    if (count(a) <= k) return nullptr;
    for (int i = B - 1; i >= 0; --i) {
      bool f = (acc >> i) & 1;
      if (count(f ? a->r : a->l) <= k) {
        k -= count(f ? a->r : a->l);
        a = f ? a->l : a->r;
      } else {
        a = f ? a->r : a->l;
      }
    }
    return a;
  }
  int order_of_key(const T b) {
    Node* a = root;
    int ret = 0;
    for (int i = B - 1; i >= 0; --i) {
      Node *l = a->l, *r = a->r;
      if ((acc >> i) & 1) swap(l, r);
      bool f = (b >> i) & 1;
      if (f) ret += count(l);
      a = f ? r : l;
      if (!a) break;
    }
    return ret;
  }
};
void ECR23E() {
  BinaryTrie<int, 30> BT;
  int Q;
  cin >> Q;
  while (Q--) {
    int t;
    cin >> t;
    if (t == 1) {
      int p;
      cin >> p;
      BT.insert(p);
    } else if (t == 2) {
      int p;
      cin >> p;
      BT.erase(p);
    } else {
      int p, l;
      cin >> p >> l;
      BT.update(p);
      auto n = BT.lower_bound(l);
      if (n) {
        int val = BT.val(n);
        cout << BT.order_of_key(val) << ln;
      } else {
        cout << BT.size() << ln;
      }
      BT.update(p);
    }
  }
}
void ECR12E() {
  int N, K;
  cin >> N >> K;
  vector<int> A(N);
  for (int i = 0; i < (N); ++i) cin >> A[i];
  BinaryTrie<int, 30> BT;
  int x = 0;
  for (int i = 0; i < (N); ++i) {
    x ^= A[i];
    BT.insert(x);
  }
  ll ans = 0;
  for (int i = 0; i < (N); ++i) {
    ans += BT.size() - BT.lower_bound_order(K);
    BT.erase(A[i]);
    BT.update(A[i]);
  }
  cout << ans << ln;
}
void dwacon5th_final_b() {
  int N;
  cin >> N;
  vector<int> A(N);
  for (int i = 0; i < (N); ++i) cin >> A[i];
  for (int i = 0; i < (N - 1); ++i) A[i + 1] ^= A[i];
  BinaryTrie<int, 30> BT;
  for (int i = 0; i < (N - 1); ++i) BT.insert(A[i]);
  for (int i = 0; i < (N - 1); ++i) {
    auto n = BT.min_element(0);
    int ans = BT.val(n);
    cout << ans << " ";
    BT.erase(n);
    BT.update(ans);
    A[N - 1] ^= ans;
  }
  cout << A[N - 1] << ln;
  auto n = BT.root;
  BT.clear(n);
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  ECR23E();
}
