#define NDEBUG

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <climits>
#include <cfloat>
#include <ctime>
#include <cassert>
#include <map>
#include <utility>
#include <set>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <sstream>
#include <complex>
#include <stack>
#include <queue>
#include <numeric>
#include <list>
#include <iomanip>
#include <fstream>
#include <bitset>

using namespace std;

#define foreach(it, c) for (__typeof__((c).begin()) it=(c).begin(); it != (c).end(); ++it)
template <typename T> void print_container(ostream& os, const T& c) { const char* _s = " "; if (!c.empty()) { __typeof__(c.begin()) last = --c.end(); foreach (it, c) { os << *it; if (it != last) os << _s; } } }
template <typename T> ostream& operator<<(ostream& os, const vector<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const set<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const multiset<T>& c) { print_container(os, c); return os; }
template <typename T> ostream& operator<<(ostream& os, const deque<T>& c) { print_container(os, c); return os; }
template <typename T, typename U> ostream& operator<<(ostream& os, const map<T, U>& c) { print_container(os, c); return os; }
template <typename T, typename U> ostream& operator<<(ostream& os, const pair<T, U>& p) { os << "(" << p.first << ", " << p.second << ")"; return os; }

template <typename T> void print(T a, int n, const string& split = " ") { for (int i = 0; i < n; i++) { cout << a[i]; if (i + 1 != n) cout << split; } cout << endl; }
template <typename T> void print2d(T a, int w, int h, int width = -1, int br = 0) { for (int i = 0; i < h; ++i) { for (int j = 0; j < w; ++j) { if (width != -1) cout.width(width); cout << a[i][j] << ' '; } cout << endl; } while (br--) cout << endl; }
template <typename T> void input(T& a, int n) { for (int i = 0; i < n; ++i) cin >> a[i]; }
#define dump(v) (cerr << #v << ": " << v << endl)

#define rep(i, n) for (int i = 0; i < (int)(n); ++i)
#define erep(i, n) for (int i = 0; i <= (int)(n); ++i)
#define all(a) (a).begin(), (a).end()
#define rall(a) (a).rbegin(), (a).rend()
#define clr(a, x) memset(a, x, sizeof(a))
#define sz(a) ((int)(a).size())
#define mp(a, b) make_pair(a, b)
#define ten(n) ((long long)(1e##n))

template <typename T, typename U> void upmin(T& a, const U& b) { a = min<T>(a, b); }
template <typename T, typename U> void upmax(T& a, const U& b) { a = max<T>(a, b); }
template <typename T> void uniq(T& a) { sort(a.begin(), a.end()); a.erase(unique(a.begin(), a.end()), a.end()); }
template <class T> string to_s(const T& a) { ostringstream os; os << a; return os.str(); }
template <class T> T to_T(const string& s) { istringstream is(s); T res; is >> res; return res; }
void fast_io() { cin.tie(0); ios::sync_with_stdio(false); }
bool in_rect(int x, int y, int w, int h) { return 0 <= x && x < w && 0 <= y && y < h; }

typedef long long ll;
typedef pair<int, int> pint;

const int dx[] = { 0, 1, 0, -1 };
const int dy[] = { 1, 0, -1, 0 };




class LCA
{
    friend class LCABuilder;
    friend LCA build_lca(vector<vector<int> >& g, int root);

private:
    int max_log;

    LCA(vector<int>& depth, vector<vector<int> >& parent, int max_log)
        : max_log(max_log), depth(depth), parent(parent) { }

public:
    vector<int> depth;
    vector<vector<int> > parent;

    int lca(int u, int v)
    {
        if (depth[u] > depth[v])
            swap(u, v);

        for (int k = 0; k < max_log; ++k)
            if ((depth[v] - depth[u]) >> k & 1)
                v = parent[k][v];

        if (u == v)
            return u;

        for (int k = max_log - 1; k >= 0; --k)
        {
            if (parent[k][u] != parent[k][v])
            {
                u = parent[k][u];
                v = parent[k][v];
            }
        }

        return parent[0][u];
    }
};
class LCABuilder
{
    friend LCA build_lca(vector<vector<int> >& g, int root);

private:
    int root, n;
    vector<vector<int> >& g;

    int max_log;
    vector<int> depth;
    vector<vector<int> > parent;

    LCABuilder(vector<vector<int> >& graph, int root)
        : root(root), n(graph.size()), g(graph), depth(n)
    {
        max_log = 0;
        for (int i = 1; i <= n; i *= 2)
            ++max_log;
        parent = vector<vector<int> >(max_log, vector<int>(n));

        init();
    }

    void calc_depth(int v, int p, int d)
    {
        parent[0][v] = p;
        depth[v] = d;

        for (int i = 0; i < (int)g[v].size(); ++i)
            if (g[v][i] != p)
                calc_depth(g[v][i], v, d + 1);
    }

    void init()
    {
        calc_depth(root, -1, 0);

        for (int k = 0; k + 1 < max_log; ++k)
        {
            for (int v = 0; v < n; ++v)
            {
                if (parent[k][v] < 0)
                    parent[k + 1][v] = -1;
                else
                    parent[k + 1][v] = parent[k][parent[k][v]];
            }
        }
    }
};
LCA build_lca(vector<vector<int> >& g, int root)
{
    LCABuilder builder(g, root);
    return LCA(builder.depth, builder.parent, builder.max_log);
}

namespace RBST
{
// #define RBST_LAZY
// #define RBST_REV

typedef int Value;

struct Node
{
    Node(Value val)
        :
            size(1), left(nullptr), right(nullptr),
            val(val)
#ifdef RBST_REV
            , rev(false)
#endif
    {
    }
    Node()
        :
            size(1), left(nullptr), right(nullptr)
#ifdef RBST_REV
            , rev(false)
#endif
    {
    }

    int size;

    Node* left;
    Node* right;

    Value val;

    // lazy
#ifdef RBST_REV
    bool rev;
#endif
};

int size(Node* t)
{
    return t ? t->size : 0;
}

Node* update(Node* t)
{
    t->size = size(t->left) + size(t->right) + 1;

    return t;
}

void push(Node* t)
{
#ifdef RBST_LAZY
    if (!t)
        return;

#ifdef RBST_REV
    if (t->rev)
    {
        t->rev = false;

        swap(t->left, t->right);
        if (t->left)
            t->left->rev ^= true;
        if (t->right)
            t->right->rev ^= true;
    }
#endif

#endif
}

#ifdef RBST_REV
void reverse(Node* t)
{
    if (!t)
        return;

    t->rev ^= true;
}
#endif


Node* merge(Node* l, Node* r)
{
    if (!l)
        return r;
    else if (!r)
        return l;

    push(l);
    push(r);

    if (rand() % (size(l) + size(r)) < size(l))
    {
        l->right = merge(l->right, r);
        return update(l);
    }
    else
    {
        r->left = merge(l, r->left);
        return update(r);
    }
}

// [0, k), (k, n)
pair<Node*, Node*> split(Node* t, int k)
{
    assert(0 <= k && k <= size(t));

    if (!t)
        return make_pair(nullptr, nullptr);

    push(t);

    if (k <= size(t->left))
    {
        auto s = split(t->left, k);
        t->left = s.second;
        return make_pair(s.first, update(t));
    }
    else
    {
        auto s = split(t->right,  k - size(t->left) - 1);
        t->right = s.first;
        return make_pair(update(t), s.second);
    }
}

// [0, k) + inserted + [k, n)
Node* insert(Node* t, int k, Node* inserted)
{
    assert(0 <= k && k <= size(t));

    auto s = split(t, k);
    return merge(merge(s.first, inserted), s.second);
}

Node* erase(Node* t, int k)
{
    assert(0 <= k && k < size(t));

    auto a = split(t, k);
    auto b = split(a.second, 1);
    delete b.first;
    return merge(a.first, b.second);
}

Node* nth(Node* t, int n)
{
    assert(0 <= n && n < size(t));

    push(t);

    if (n < size(t->left))
        return nth(t->left, n);
    else if (n > size(t->left))
        return nth(t->right, n - size(t->left) - 1);
    else
        return t;
}

// precondition: pos is acending
vector<Node*> split(Node* t, const vector<int>& pos)
{
    vector<Node*> res(pos.size() + 1);
    for (int i = (int)pos.size() - 1; i >= 0; --i)
    {
        auto s = split(t, pos[i]);
        res[i + 1] = s.second;
        t = s.first;
    }
    res[0] = t;
    return res;
}

Node* merge(const vector<Node*>& ts)
{
    Node* root = nullptr;
    for (auto t : ts)
        root = merge(root, t);
    return root;
}

void _list_val(Node* t, vector<Value>& val)
{
    if (!t)
        return;

    _list_val(t->left, val);
    _list_val(t->right, val);

    val.push_back(t->val);
}
vector<int> list_val(Node* root)
{
    vector<Value> val;
    _list_val(root, val);
    return val;
}

int lower_bound_index(Node* t, Value val)
{
    if (!t)
        return 0;

    if (val <= t->val)
        return lower_bound_index(t->left, val);
    else
        return size(t->left) + 1 + lower_bound_index(t->right, val);
}
int upper_bound_index(Node* t, Value val)
{
    if (!t)
        return 0;

    if (val < t->val)
        return upper_bound_index(t->left, val);
    else
        return size(t->left) + 1 + upper_bound_index(t->right, val);
}

Node* ordered_insert(Node* t, Node* inserted)
{
    return insert(t, lower_bound_index(t, inserted->val), inserted);
}


// persistent
Node* persistent_merge(Node* l, Node* r)
{
    if (!l)
        return r;
    else if (!r)
        return l;

    if (rand() % (size(l) + size(r)) < size(l))
    {
        Node* copied_l = new Node(*l);
        copied_l->right = persistent_merge(copied_l->right, r);
        return update(copied_l);
    }
    else
    {
        Node* copied_r = new Node(*r);
        copied_r->left = persistent_merge(l, copied_r->left);
        return update(copied_r);
    }
}

// [0, k), (k, n)
pair<Node*, Node*> persistent_split(Node* t, int k)
{
    assert(0 <= k && k <= size(t));

    if (!t)
        return make_pair(nullptr, nullptr);

    Node* copied_t = new Node(*t);
    if (k <= size(t->left))
    {
        auto s = persistent_split(copied_t->left, k);
        copied_t->left = s.second;
        return make_pair(s.first, update(copied_t));
    }
    else
    {
        auto s = persistent_split(copied_t->right,  k - size(copied_t->left) - 1);
        copied_t->right = s.first;
        return make_pair(update(copied_t), s.second);
    }
}

// [0, k) + inserted + [k, n)
Node* persistent_insert(Node* t, int k, Node* inserted)
{
    assert(0 <= k && k <= size(t));

    auto s = persistent_split(t, k);
    return persistent_merge(persistent_merge(s.first, inserted), s.second);
}

Node* persistent_ordered_insert(Node* t, Node* inserted)
{
    return persistent_insert(t, lower_bound_index(t, inserted->val), inserted);
}


} // namespace RBST



using namespace RBST;

vector<int> x;
vector<vector<int>> g;
vector<Node*> btrees;
void build_btrees(int pos, int par, Node* parent_btree)
{
    btrees[pos] = persistent_ordered_insert(parent_btree, new Node(x[pos]));

    for (int to : g[pos])
        if (to != par)
            build_btrees(to, pos, btrees[pos]);
}
int kth(int v, int w, int lc, int val)
{
    int kth = 0;
    kth += upper_bound_index(btrees[v], val);
    kth += upper_bound_index(btrees[w], val);
    kth -= 2 * upper_bound_index(btrees[lc], val);
    if (x[lc] <= val)
        ++kth;
    return kth;
}
int main()
{
    fast_io();

    int n, q;
    cin >> n >> q;

    x.resize(n);
    input(x, n);
    g.resize(n);
    rep(i, n - 1)
    {
        int a, b;
        cin >> a >> b;
        --a, --b;
        g[a].push_back(b);
        g[b].push_back(a);
    }

    LCA lca = build_lca(g, 0);

    btrees.resize(n);
    build_btrees(0, -1, nullptr);

    rep(qi, q)
    {
        int v, w, lth;
        cin >> v >> w >> lth;
        --v, --w, --lth;
        const int lc = lca.lca(v, w);

        int low = -1, high = ten(9) + 11;
        while (high - low > 1)
        {
            int mid = (low + high) / 2;

            if (kth(v, w, lc, mid) <= lth)
                low = mid;
            else
                high = mid;
        }
        cout << high << endl;
    }
}

Measured memory_bytes: 235116