#include <iostream>
#include <cstring>
#define int long long
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
const int N = 20010;
const int M = 60, K = 16;
struct LiBasis
{
int v[M + 1];
int operator[] (const int x)const {return v[x];}
int query()
{
int res = 0;
for (int i = M; i >= 0; i -- )
res = max(res, res ^ v[i]);
return res;
}
void add(int x)
{
for (int i = M; i >= 0; i -- )
if (x >> i & 1)
if (!v[i]) {v[i] = x; break;}
else x ^= v[i];
}
void insert(LiBasis b)
{
for (int i = M; i >= 0; i -- )
if (b[i]) add(b[i]);
}
}B[N][K];
LiBasis operator+ (LiBasis a, const LiBasis b)
{
a.insert(b);
return a;
}
int n, m;
int h[N], e[N << 1], ne[N << 1], idx;
int q[N], w[N];
int dep[N], fa[N][K];
inline void add(int a, int b)
{
e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}
inline void bfs()
{
int hh = 0, tt = 0;
memset(dep, 0x3f, sizeof dep);
dep[0] = 0, dep[1] = 1, q[0] = 1;
while (hh <= tt)
{
int t = q[hh ++ ];
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (dep[j] > dep[t] + 1)
{
dep[j] = dep[t] + 1, q[ ++ tt] = j;
fa[j][0] = t, B[j][0].add(w[j]);
for (int k = 1; k < K; k ++ )
{
fa[j][k] = fa[fa[j][k - 1]][k - 1];
B[j][k] = B[j][k - 1] + B[fa[j][k - 1]][k - 1];
}
}
}
}
}
LiBasis lca(int a, int b)
{
LiBasis res;
memset(res.v, 0, sizeof res.v);
if (dep[a] < dep[b]) swap(a, b);
for (int i = K - 1; i >= 0; i -- )
if (dep[fa[a][i]] >= dep[b])
res = res + B[a][i], a = fa[a][i];
if (a == b) return res.add(w[a]), res;
for (int i = K - 1; i >= 0; i -- )
if (fa[a][i] != fa[b][i])
{
res = res + B[a][i] + B[b][i];
a = fa[a][i], b = fa[b][i];
}
res.add(w[fa[a][0]]), res.add(w[a]), res.add(w[b]);
return res;
}
signed main()
{
int a, b;
memset(h, -1, sizeof h);
scanf("%lld%lld", &n, &m);
for (int i = 1; i <= n; i ++ )
scanf("%lld", &w[i]);
for (int i = 1; i < n; i ++ )
{
scanf("%lld%lld", &a, &b);
add(a, b), add(b, a);
}
bfs();
while (m -- )
{
int res = 0;
scanf("%lld%lld", &a, &b);
LiBasis p = lca(a, b);
for (int i = M; i >= 0; i -- )
res = max(res, res ^ p[i]);
printf("%lld\n", res);
}
return 0;
}