// Author : AhmedQassem_
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
#define endl '\n'
//#define int ll
#define ep cout << fixed << setprecision(12)
#define all(x) (x).begin(), (x).end()
#define allr(x) (x).rbegin(), (x).rend()
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 + 7;
//const int mod = 998244353;
const ld PI = acosl(-1.0L);
int dx[] = {0,0,1,-1};
int dy[] = {1,-1,0,0};
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
int lcm(int a, int b) { return a / gcd(a, b) * b; }
void fileio() {
#ifndef ONLINE_JUDGE
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
}
void fastio() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
}
const int N = 2e5+5 ,M = 23;
vector<vector<pair<int,int>>>adj(N);
vector<int>tin(N) , tout(N) , val(N);
int timer = 0;
void dfs(int u , int cnt = 0, int p = -1){
tin[u] = ++ timer;
val[u] = cnt;
for(auto[v,w] : adj[u]){
if(v != p){
dfs(v,cnt ^ w , u);
}
}
tout[u] = timer;
}
struct BinaryTrie {
static const int MAX_BIT = 32; // adjust for the max number of bits needed
struct Node {
int nxt[2]; // next nodes for bit 0 and 1
int cnt; // how many numbers pass through this node
int end; // how many numbers end at this node
Node() { nxt[0] = nxt[1] = 0; cnt = end = 0; }
};
vector<Node> tr;
BinaryTrie(int reserve_nodes = 0) { if(reserve_nodes) tr.reserve(reserve_nodes); tr.push_back(Node()); } // constructor
int add_node() { tr.push_back(Node()); return (int)tr.size() - 1; } // create new node
int size() const { return tr[0].cnt; } // total numbers
int nodes() const { return (int)tr.size(); } // total nodes
bool empty() const { return tr[0].cnt == 0; } // is trie empty
void clear() { tr.clear(); tr.push_back(Node()); } // reset trie
void insert(unsigned long long x) { // insert number x
int u = 0; tr[u].cnt++;
for(int i = MAX_BIT; i >= 0; --i) {
int b = (x >> i) & 1ULL;
if(!tr[u].nxt[b]) tr[u].nxt[b] = add_node();
u = tr[u].nxt[b]; tr[u].cnt++;
}
tr[u].end++;
}
int count_exact(unsigned long long x) const { // occurrences of x
int u = 0;
for(int i = MAX_BIT; i >= 0; --i) {
int b = (x >> i) & 1ULL;
if(!tr[u].nxt[b]) return 0;
u = tr[u].nxt[b];
}
return tr[u].end;
}
bool contains(unsigned long long x) const { return count_exact(x) > 0; } // check if x exists
bool erase(unsigned long long x) { // remove one occurrence of x
if(count_exact(x) == 0) return false;
int u = 0; tr[u].cnt--;
for(int i = MAX_BIT; i >= 0; --i) {
int b = (x >> i) & 1ULL;
u = tr[u].nxt[b]; tr[u].cnt--;
}
tr[u].end--; return true;
}
unsigned long long max_xor_value(unsigned long long x) const { // max XOR with x
if(empty()) return 0;
int u = 0; unsigned long long res = 0;
for(int i = MAX_BIT; i >= 0; --i) {
int b = (x >> i) & 1ULL, want = b ^ 1;
if(tr[u].nxt[want] && tr[tr[u].nxt[want]].cnt > 0) { res |= (1ULL << i); u = tr[u].nxt[want]; }
else u = tr[u].nxt[b];
}
return res;
}
unsigned long long min_xor_value(unsigned long long x) const { // min XOR with x
if(empty()) return 0;
int u = 0; unsigned long long res = 0;
for(int i = MAX_BIT; i >= 0; --i) {
int b = (x >> i) & 1ULL;
if(tr[u].nxt[b] && tr[tr[u].nxt[b]].cnt > 0) u = tr[u].nxt[b];
else { res |= (1ULL << i); u = tr[u].nxt[b ^ 1]; }
}
return res;
}
unsigned long long max_xor_number(unsigned long long x) const { // number giving max XOR with x
if(empty()) return ULLONG_MAX;
int u = 0; unsigned long long y = 0;
for(int i = MAX_BIT; i >= 0; --i) {
int b = (x >> i) & 1ULL, want = b ^ 1;
if(tr[u].nxt[want] && tr[tr[u].nxt[want]].cnt > 0) { y |= (1ULL << i); u = tr[u].nxt[want]; }
else { y |= (unsigned long long)b << i; u = tr[u].nxt[b]; }
}
return y;
}
unsigned long long min_xor_number(unsigned long long x) const { // number giving min XOR with x
if(empty()) return ULLONG_MAX;
int u = 0; unsigned long long y = 0;
for(int i = MAX_BIT; i >= 0; --i) {
int b = (x >> i) & 1ULL;
if(tr[u].nxt[b] && tr[tr[u].nxt[b]].cnt > 0) { y |= (unsigned long long)b << i; u = tr[u].nxt[b]; }
else { y |= (unsigned long long)(b ^ 1) << i; u = tr[u].nxt[b ^ 1]; }
}
return y;
}
unsigned long long kth_smallest(long long k) const { // kth smallest number
if(k <= 0 || k > tr[0].cnt) return ULLONG_MAX;
int u = 0; unsigned long long res = 0;
for(int i = MAX_BIT; i >= 0; --i) {
int left = tr[u].nxt[0], left_cnt = left ? tr[left].cnt : 0;
if(k <= left_cnt) u = left;
else { k -= left_cnt; res |= (1ULL << i); u = tr[u].nxt[1]; }
}
return res;
}
long long count_less_than(unsigned long long x) const { // count numbers < x
long long ans = 0; int u = 0;
for(int i = MAX_BIT; i >= 0; --i) {
int b = (x >> i) & 1ULL;
if(b == 1) { int left = tr[u].nxt[0]; if(left) ans += tr[left].cnt; u = tr[u].nxt[1]; }
else u = tr[u].nxt[0];
if(!u) break;
}
return ans;
}
long long count_xor_less_than(unsigned long long x, unsigned long long k) const { // count numbers y: (x^y) < k
long long ans = 0; int u = 0;
for(int i = MAX_BIT; i >= 0; --i) {
int xb = (x >> i) & 1ULL, kb = (k >> i) & 1ULL;
if(!u) break;
if(kb == 1) { int same = tr[u].nxt[xb]; if(same) ans += tr[same].cnt; u = tr[u].nxt[xb ^ 1]; }
else u = tr[u].nxt[xb];
}
return ans;
}
unsigned long long lower_bound_value(unsigned long long x) const { // first number >= x
long long rk = count_less_than(x) + 1;
if(rk > tr[0].cnt) return ULLONG_MAX;
return kth_smallest(rk);
}
unsigned long long upper_bound_value(unsigned long long x) const { // first number > x
if(x == ULLONG_MAX) return ULLONG_MAX;
long long rk = count_less_than(x + 1) + 1;
if(rk > tr[0].cnt) return ULLONG_MAX;
return kth_smallest(rk);
}
};
struct Node
{
BinaryTrie val;
Node() {
val = BinaryTrie();
}
Node(int x) {
val = BinaryTrie();
val.insert(x);
}
void change(int x) {
val.erase(x);
}
};
struct SegTree
{
int tree_size;
vector<Node> SegData;
SegTree(int n)
{
tree_size = 1;
while (tree_size < n) tree_size *= 2;
SegData.assign(2 * tree_size, Node());
}
// Node merge(Node& lf, Node& ri)
// {
// Node ret = Node();
// return ret;
// }
void init(vector<int>& arr, int ni, int lx, int rx)
{
SegData[ni] = Node();
for(int i = lx ; i < rx ; i++){
SegData[ni].val.insert(arr[i]);
}
if(rx - lx == 1)return;
int mid = (rx + lx) / 2;
init(arr, 2 * ni + 1, lx, mid);
init(arr, 2 * ni + 2, mid, rx);
//SegData[ni] = merge(SegData[2 * ni + 1], SegData[2 * ni + 2]);
}
void init(vector<int>& arr) { init(arr, 0, 0, tree_size); }
void set(int idx, int val, int ni, int lx, int rx)
{
if (rx - lx == 1)
{
SegData[ni].change(val); return;
}
int mid = (rx + lx) / 2;
if (idx < mid)
{
set(idx, val, 2 * ni + 1, lx, mid);
SegData[ni].change(val);
}
else
{
set(idx, val, 2 * ni + 2, mid, rx);
SegData[ni].change(val);
}
//SegData[ni] = merge(SegData[2 * ni + 1], SegData[2 * ni + 2]);
}
void set(int idx, int val)
{
set(idx, val, 0, 0, tree_size);
}
int get(int l, int r, int val, int ni, int lx, int rx)
{
if (lx >= l && rx <= r) return SegData[ni].val.max_xor_value(val);
if (lx >= r || rx <= l) return 0;
int mid = (rx + lx) / 2;
int lf = get(l, r,val, 2 * ni + 1, lx, mid);
int ri = get(l, r,val, 2 * ni + 2, mid, rx);
return max(lf, ri);
}
int get(int l, int r , int val) { return get(l, r,val, 0, 0, tree_size); }
};
void Magek() {
int q; cin >> q;
deque<array<int,4>>qu;
int id = 2;
for(int i = 0 ; i < q ; i++){
string s;
int u,v; cin >> s >> u >> v;
qu.push_front({s == "Add" , u , v,id});
if(s == "Add"){
adj[u].push_back({id , v});
adj[id++].push_back({u , v});
}
}
vector<int>a(id);
dfs(1);
for(int i = 1 ; i < id ; i++){
a[tin[i]-1] = val[i];
}
SegTree tree(id);
tree.init(a);
deque<int>ans;
for(auto& i : qu){
int t = i[0] , u = i[1] , v = i[2] , idx = i[3];
if(t == 1){
tree.set(tin[idx]-1,val[idx]);
}
else{
ans.push_front(tree.get(tin[v]-1 , tout[v] ,val[u]));
}
}
for(int i : ans){
cout << i << endl;
}
}
int32_t main() {
//fileio();
fastio();
int t = 1;
//cin >> t;
while (t--) Magek();
return 0;
}