#include <bits/stdc++.h>

using namespace std;

template< typename Monoid >
struct PersistentSegmentTree
{
  using F = function< Monoid(Monoid, Monoid) >;

  struct Node
  {
    Monoid data;
    Node *l, *r;

    Node(const Monoid &data) : data(data) {}
  };

  int sz;
  const F f;
  const Monoid M1;

  PersistentSegmentTree(const F f, const Monoid &M1) : f(f), M1(M1) {}

  Node *build(vector< Monoid > &v)
  {
    sz = (int) v.size();
    return build(0, (int) v.size(), v);
  }

  Node *build(int l, int r, vector< Monoid > &v)
  {
    if(l + 1 >= r) {
      return new Node(v[l]);
    } else {
      auto L = build(l, (l + r) >> 1, v);
      auto R = build((l + r) >> 1, r, v);
      auto p = new Node(f(L->data, R->data));
      p->l = L;
      p->r = R;
      return p;
    }
  }

  Node *update(int a, const Monoid &x, Node *k, int l, int r)
  {
    if(r <= a || a + 1 <= l || !k) {
      return k;
    } else if(a <= l && r <= a + 1) {
      return new Node(x);
    } else {
      auto L = update(a, x, k->l, l, (l + r) >> 1);
      auto R = update(a, x, k->r, (l + r) >> 1, r);
      k = new Node(f(L->data, R->data));
      k->l = L;
      k->r = R;
      return k;
    }
  }

  Node *update(Node *t, int k, const Monoid &x)
  {
    return update(k, x, t, 0, sz);
  }

  Monoid query(int a, int b, Node *k, int l, int r)
  {
    if(r <= a || b <= l || !k) {
      return M1;
    } else if(a <= l && r <= b) {
      return k->data;
    } else {
      return f(query(a, b, k->l, l, (l + r) >> 1),
               query(a, b, k->r, (l + r) >> 1, r));
    }
  }

  Monoid query(Node *t, int a, int b)
  {
    return query(a, b, t, 0, sz);
  }
};

struct CentroidPathDecomposition
{
  struct Centroid
  {
    int ParIndex, ParDepth, Deep;
    vector< int > node;

    Centroid(int idx, int dep, int deep) : ParIndex(idx), ParDepth(dep), Deep(deep) {}

    inline size_t size()
    {
      return (node.size());
    }

    inline int &operator[](int k)
    {
      return (node[k]);
    }

    inline pair< int, int > Up()
    {
      return (make_pair(ParIndex, ParDepth));
    }
  };

  vector< vector< int > > graph;
  vector< int > SubTreeSize, NextPath;
  vector< int > TreeIndex, TreeDepth;
  vector< Centroid > Centroids;

  void BuildSubTreeSize()
  {
    stack< pair< int, int > > s;
    s.emplace(0, -1);
    while(!s.empty()) {
      auto p = s.top();
      s.pop();
      if(~SubTreeSize[p.first]) {
        NextPath[p.first] = -1;
        for(auto &to : graph[p.first]) {
          if(p.second == to) continue;
          SubTreeSize[p.first] += SubTreeSize[to];
          if(NextPath[p.first] == -1 || SubTreeSize[NextPath[p.first]] < SubTreeSize[to]) {
            NextPath[p.first] = to;
          }
        }
      } else {
        s.push(p);
        SubTreeSize[p.first] = 1;
        for(auto &to : graph[p.first]) {
          if(p.second != to) s.emplace(to, p.first);
        }
      }
    }
  }

  void BuildPath()
  {
    stack< pair< int, int > > s;
    Centroids.emplace_back(-1, -1, 0);
    s.emplace(0, -1);
    TreeIndex[0] = 0;
    while(!s.empty()) {
      auto p = s.top();
      s.pop();
      TreeDepth[p.first] = (int) Centroids[TreeIndex[p.first]].size();
      for(auto &to : graph[p.first]) {
        if(p.second == to) continue;
        if(to == NextPath[p.first]) { // Centroid-Path
          TreeIndex[to] = TreeIndex[p.first];
        } else {                  // Not Centroid-Path
          TreeIndex[to] = (int) Centroids.size();
          Centroids.emplace_back(TreeIndex[p.first], TreeDepth[p.first], Centroids[TreeIndex[p.first]].Deep + 1);
        }
        s.emplace(to, p.first);
      }
      Centroids[TreeIndex[p.first]].node.emplace_back(p.first);
    }
  }

  void AddEdge(int x, int y)
  {
    graph[x].push_back(y);
    graph[y].push_back(x);
  }

  virtual void Build()
  {
    BuildSubTreeSize();
    BuildPath();
  }

  inline size_t size()
  {
    return (Centroids.size());
  }

  inline pair< int, int > Information(int idx)
  {
    return (make_pair(TreeIndex[idx], TreeDepth[idx]));
  }

  inline Centroid &operator[](int k)
  {
    return (Centroids[k]);
  }

  inline int LCA(int a, int b)
  {
    int TreeIdxA, TreeDepthA, TreeIdxB, TreeDepthB;
    tie(TreeIdxA, TreeDepthA) = Information(a);
    tie(TreeIdxB, TreeDepthB) = Information(b);
    while(TreeIdxA != TreeIdxB) {
      if(Centroids[TreeIdxA].Deep > Centroids[TreeIdxB].Deep) {
        tie(TreeIdxA, TreeDepthA) = Centroids[TreeIdxA].Up();
      } else {
        tie(TreeIdxB, TreeDepthB) = Centroids[TreeIdxB].Up();
      }
    }
    if(TreeDepthA > TreeDepthB) swap(TreeDepthA, TreeDepthB);
    return (Centroids[TreeIdxA][TreeDepthA]);
  }

  inline virtual void query(int a, int b, const function< void(int, int, int) > &f)
  {
    int TreeIdxA, TreeDepthA, TreeIdxB, TreeDepthB;
    tie(TreeIdxA, TreeDepthA) = Information(a);
    tie(TreeIdxB, TreeDepthB) = Information(b);
    while(TreeIdxA != TreeIdxB) {
      if(Centroids[TreeIdxA].Deep > Centroids[TreeIdxB].Deep) {
        f(TreeIdxA, 0, TreeDepthA + 1);
        tie(TreeIdxA, TreeDepthA) = Centroids[TreeIdxA].Up();
      } else {
        f(TreeIdxB, 0, TreeDepthB + 1);
        tie(TreeIdxB, TreeDepthB) = Centroids[TreeIdxB].Up();
      }
    }
    if(TreeDepthA > TreeDepthB) swap(TreeDepthA, TreeDepthB);
    f(TreeIdxA, TreeDepthA, TreeDepthB + 1);
  }

  CentroidPathDecomposition(int SZ)
  {
    graph.resize(SZ);
    SubTreeSize.assign(SZ, -1);
    NextPath.resize(SZ);
    TreeIndex.resize(SZ);
    TreeDepth.resize(SZ);
  }
};

PersistentSegmentTree< int > seg([](int a, int b) { return a + b; }, 0);
PersistentSegmentTree< int >::Node *nodes[100000];

int N, Q, X[100000];
vector< int > g[100000];
int parent[100000];

void dfs(int idx, int par, PersistentSegmentTree< int >::Node *par_set)
{
  parent[idx] = par;
  nodes[idx] = par_set = seg.update(par_set, X[idx], seg.query(par_set, X[idx], X[idx] + 1) + 1);
  for(auto &to : g[idx]) if(to != par) dfs(to, idx, par_set);
}


int main()
{
  scanf("%d %d", &N, &Q);
  CentroidPathDecomposition gg(N);
  vector< int > vs;
  for(int i = 0; i < N; i++) {
    scanf("%d", &X[i]);
    vs.emplace_back(X[i]);
  }
  sort(begin(vs), end(vs));
  vs.erase(unique(begin(vs), end(vs)), end(vs));
  for(int i = 0; i < N; i++) {
    X[i] = lower_bound(begin(vs), end(vs), X[i]) - begin(vs);
  }
  for(int i = 1; i < N; i++) {
    int x, y;
    scanf("%d %d", &x, &y);
    --x, --y;
    g[x].emplace_back(y);
    g[y].emplace_back(x);
    gg.AddEdge(x, y);
  }
  vector< int > order(vs.size());
  dfs(0, -1, seg.build(order));
  gg.Build();

  for(int i = 0; i < Q; i++) {
    int x, y, z;
    scanf("%d %d %d", &x, &y, &z);
    --x, --y;
    int lca = gg.LCA(x, y);
    int ng = -1, ok = (int) vs.size() - 1;
    auto sum = [&](int v)
    {
      int ret = 0;
      ret += seg.query(nodes[x], 0, v + 1);
      ret += seg.query(nodes[y], 0, v + 1);
      ret -= X[lca] <= v;
      if(lca) ret -= 2 * seg.query(nodes[parent[lca]], 0, v + 1);
      return ret;
    };
    while(ok - ng > 1) {
      int mid = (ok + ng) >> 1;
      if(sum(mid) >= z) ok = mid;
      else ng = mid;
    }
    printf("%d\n", vs[ok]);
  }
}


Measured memory_bytes: 117640