#include <bits/stdc++.h>
using int64 = long long;
using uchar = unsigned char;
constexpr int maxn(100000);
constexpr int mxbit(8);
constexpr int full((1 << mxbit) - 1);
constexpr int hfull(full << mxbit);
template <class _Tp>
inline void chkMax(_Tp &x, const _Tp &y) {
  (x < y) && (x = y);
}
namespace IOManager {
constexpr int FILESZ(131072);
char buf[FILESZ];
const char *ibuf = buf, *tbuf = buf;
constexpr int OSIZE(65536);
unsigned char OBUF[OSIZE + 128];
constexpr unsigned char *OT(OBUF + OSIZE);
struct IOManager {
  IOManager() : OS(OBUF - 1) {}
  ~IOManager() {
    fwrite(OBUF, 1, OS - OBUF + 1, stdout);
    fclose(stdout);
  }
  inline char gc() {
    return (ibuf == tbuf) &&
                   (tbuf = (ibuf = buf) + fread(buf, 1, FILESZ, stdin),
                    ibuf == tbuf)
               ? EOF
               : *ibuf++;
  }
  template <class _Tp>
  inline operator _Tp() {
    _Tp s = 0u;
    char c = gc();
    for (; c < 48; c = gc())
      ;
    for (; c > 47; c = gc()) s = (_Tp)(s * 10u + c - 48u);
    return s;
  }
  unsigned char *OS;
  inline void Flush() {
    fwrite(OBUF, 1, OS - OBUF + 1, stdout);
    OS = OBUF - 1;
  }
  inline IOManager &operator<<(const unsigned char &c) {
    if (OS > OT) Flush();
    return (*++OS = c, *this);
  }
  inline IOManager &operator<<(const char &c) {
    if (OS > OT) Flush();
    return (*++OS = c, *this);
  }
  template <class _Tp>
  inline IOManager &operator<<(_Tp s) {
    static unsigned char OStack[30], *Top = OStack;
    static _Tp y;
    if (OS > OT) Flush();
    if (s) {
      for (; s; *++Top = s - y * 10 + 48, s = y) y = s / 10;
      for (; Top != OStack;) *++OS = *Top--;
    } else
      *++OS = '0';
    return *this;
  }
};
}  // namespace IOManager
IOManager::IOManager io;
struct Edge {
  int v;
  Edge *las;
  inline Edge *init(const int &to, Edge *const &ls) {
    return v = to, las = ls, this;
  }
} * las[maxn + 1];
inline void AddEdge() {
  static Edge pool[maxn << 1], *alc = pool - 1;
  const int u = io, v = io;
  las[u] = (++alc)->init(v, las[u]);
  las[v] = (++alc)->init(u, las[v]);
}
int dp[maxn + 1][1 << mxbit], a[maxn + 1], up[maxn + 1], Fa[maxn + 1],
    dep[maxn + 1];
void precalc(const int &now) {
  for (Edge *o = las[now]; o; o = o->las)
    if (o->v != Fa[now])
      Fa[o->v] = now, dep[o->v] = dep[now] + 1, precalc(o->v);
  if (full <= dep[now]) {
    int t = now;
    for (int st = 0; st <= full; ++st, t = Fa[t])
      chkMax(dp[now][full - (a[t] >> mxbit)], hfull | (st ^ a[t]));
    up[now] = t;
    for (int i = 1, j = (1 << mxbit); i <= full; i += i, j += j)
      for (int st = 0; st <= full; ++st)
        if (!~dp[now][st] && ~dp[now][st ^ i])
          dp[now][st] = dp[now][st ^ i] ^ j;
  }
}
int main() {
  const int n = io;
  int q = io;
  for (int i = 1; i <= n; ++i) a[i] = io;
  for (int i = n - 1; i; --i) AddEdge();
  memset(dp, -1, sizeof dp);
  for (precalc(1); q; --q) {
    const int u = io;
    int v = io;
    const int l = dep[v] - dep[u] + 1;
    int ans = 0;
    for (int i = 0; i < (l >> mxbit); ++i, v = up[v]) chkMax(ans, dp[v][i]);
    for (int i = ((l >> mxbit) << mxbit); i < l; ++i, v = Fa[v])
      chkMax(ans, a[v] ^ i);
    io << ans << '\n';
  }
  return 0;
}
