#include <algorithm>
#include <vector>
using namespace std;
const int N = 1e5 + 100;
const int NUM = 30; // 根据数据范围变化
const int M = N * (NUM + 1);
int root1[M], root2[M], max_id[M]; // root记录版本号,Max_Id是当前节点在区间哪个位置
int tr11 [M][2];
int tr2 [M][2];
long long int idx;
int h[N*2];
int e[N * 2];
int ne[N * 2];
int add_idx;
int w[N + 100];
bool st[N*2]; // 记录节点是否被访问过,访问过则标记为true
int dfc;
int in[N*2], out[N*2];
int depth[N*2];
int f[N*2][25];
int lg[N*2];
int val[N*2];
// a所对应的单链表中插入b a作为根
void add(int a, int b) {
e[add_idx] = b, ne[add_idx] = h[a], h[a] = add_idx++;
}
void l_dfs(int now, int fath) {
f[now][0] = fath;
depth[now] = depth[fath] + 1;
for (int i = 1; i <= lg[depth[now]]; ++i)
f[now][i] = f[f[now][i - 1]][i - 1];
for (int i = h[now]; i != -1; i = ne[i]) {
if (e[i] != fath) l_dfs(e[i], now);
}
}
int _query(int x, int y) {
if (depth[x] < depth[y]) swap(x, y);
while (depth[x] > depth[y])
x = f[x][lg[depth[x] - depth[y]] - 1];
if (x == y) return x;
for (int i = lg[depth[x]] - 1; i >= 0; i--) {
if (f[x][i] != f[y][i])
x = f[x][i],
y = f[y][i];
}
return f[x][0];
}
void insert(int j, int k, int p, int q, int(*tr)[2]) {
if (k < 0) {
max_id[q] = in[j];
// cout << max_id[q] << ";" << endl;;
return;
}
// cout << tr[1][1]; // 输出调试信息
int s = w[j];
int v = ((s >> k) & 1); // 获取当前位的值(0 或 1)
if (p) tr[q][v ^ 1] = tr[p][v ^ 1]; // 如果 p 不为 0,复制 p 的另一个子节点到 q
// cout << "hello"; // 输出调试信息
tr[q][v] = ++idx; // 创建新节点并更新 tr[q][v]
insert(j, k - 1, tr[p][v], tr[q][v], tr); // 递归插入剩余的位
max_id[q] = max(max_id[tr[q][1]], max_id[tr[q][0]]); // 更新 max_id[q]
}
void dfs(int u, int fa) {
root2[u] = ++idx;
in[u] = ++dfc;
val[in[u]] = w[u];
root1[dfc] = ++idx;
root2[u]=++idx;
insert(u, NUM, root2[fa], root2[u], tr2);
// cout << u << ",";
insert(u, NUM, root1[dfc - 1], root1[dfc], tr11);
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (!st[j]) {
st[j] = true;
dfs(j, u);
}
}
out[u] = dfc; //cout <<u<<" "<<out[u]<< endl;
}
int query(int L, int R, int C, int(*tr)[2]) {
int p = root1[R];
// cout << "r:" << p << endl;
for (int i = NUM; i >= 0; i--) {
int v = ((C >> i) & 1);
//cout << max_id[p] << "."; cout << max_id[tr[p][v ^ 1]] << endl;;
if (max_id[tr[p][v ^ 1]] >= L) p = tr[p][v ^ 1];
else p = tr[p][v];
}
//cout << max_id[p] << endl;
//cout << val[max_id[p]] << endl;
return val[max_id[p]] ^ C;
}
int query2(int L, int R, int C, int(*tr)[2]) {
int p = root2[R];
// cout << "r:" << p << endl;
for (int i = NUM; i >= 0; i--) {
int v = ((C >> i) & 1);
//cout << max_id[p] << "."; cout << max_id[tr[p][v ^ 1]] << endl;;
if (max_id[tr[p][v ^ 1]] >= L) p = tr[p][v ^ 1];
else p = tr[p][v];
}
//cout << max_id[p] << endl;
// cout << val[max_id[p]] << endl;
return val[max_id[p]] ^ C;
}
int main() {
//ios::sync_with_stdio(false);cin.tie(nullptr);
int n, m;
scanf("%d %d", &n, &m);
for (int i = 0; i <= 2 * n + 10; i++) h[i] = -1;
for (int i = 1; i <= n; i++) {
cin >> w[i];
}
for (int i = 1; i <= n - 1; i++) {
int a, b;
cin >> a >> b;
add(a, b);
add(b, a);
}
for (int i = 1; i <= n; i++) {
lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
// 这里存的是logi(以2为底)在加1
//常数优化
}
in[1] = ++idx;
max_id[0] = -1;
root1[0] = ++idx;
insert(0, NUM, 0, root1[0], tr11);
st[1] = true;
dfs(1, 0);
l_dfs(1, 0);
root2[0] = ++idx;
insert(0, NUM, 0, root2[0], tr2);
while (m--) {
int op;
cin >> op;
// cout << "dsauid";
if (op == 1) {
// cout <<"dasd" << in[6] << endl;
int x, z;
cin >> x >> z;
// cout << in[x] << endl;;
// cout << out[x] << endl;
int ans=max(w[x]^z,query(in[x], out[x], z, tr11) );
cout<<ans<<endl;
}
else {
int a, b, c;
cin >> a >> b >> c;
int x = _query(a, b);
// cout << "lac:" << x << endl;
int ans=max(w[a]^c,w[b]^c);
ans=max(ans,c^w[x]);
ans = max(query2(x, a,c,tr2), query2(x, b,c,tr2));
cout << ans << endl;
}
}
// 将一个区间的异或和处理为前缀和,则两个数的异或则是这个区间的异或和
// 释放动态分配的内存
return 0;
}```