#include <cmath>
#include <cstdlib>
#include <iostream>
#include <random>
#include <vector>
using namespace std;

// Randomized Binary Search Tree
// infix, 0-based

typedef int type;

mt19937 engine;
uniform_int_distribution<int> rnd;

struct RBST {
	type value;
	int size;
	RBST *left, *right;

	RBST(int v):value(v), size(1), left(nullptr), right(nullptr) {}

	void update() {
		size = 1;

		if(left) {
			size += left->size;
		}

		if(right) {
			size += right->size;
		}
	}
};

inline int node_size(const RBST *x) {
	return x ? x->size : 0;
}

RBST *merge(RBST *x, RBST *y) {
	if(!x) return y;
	if(!y) return x;

	if(rnd(engine) % (x->size + y->size) < x->size) {
		RBST *res = new RBST(x->value);
		res->left = x->left;
		res->right = merge(x->right, y);
		res->update();
		return res;
	}
	else {
		RBST *res = new RBST(y->value);
		res->left = merge(x, y->left);
		res->right = y->right;
		res->update();
		return res;
	}
}

typedef pair<RBST *, RBST *> P;

P split(RBST *x, int num) {
	if(!x) return P(nullptr, nullptr);

	RBST *res = new RBST(x->value);
	const int l_size = node_size(x->left);

	if(l_size < num) {
		const P tmp = split(x->right, num - l_size - 1);
		res->left = x->left;
		res->right = tmp.first;
		res->update();
		return P(res, tmp.second);
	}
	else {
		const P tmp = split(x->left, num);
		res->left = tmp.second;
		res->right = x->right;
		res->update();
		return P(tmp.first, res);
	}
}

RBST *insert(RBST *x, int pos, type value) {
	RBST *new_node = new RBST(value);
	const P tmp = split(x, pos);
	return merge(merge(tmp.first, new_node), tmp.second);
}

RBST *erase(RBST *x, int pos) {
	P tmp = split(x, pos);
	RBST *left = tmp.first;
	tmp = split(tmp.second, 1);
	delete tmp.first;
	return merge(left, tmp.second);
}

// [l, r)
type query(RBST *x, type v) {
	if(!x) return 0;
	if(v < x->value) return query(x->left, v);
	return node_size(x->left) + 1 + query(x->right, v);
}

#include <cassert>
void dfs(RBST *x) {
	if(!x) return;

	if(x->left) {
		assert(x->left->value <= x->value);
		dfs(x->left);
	}
	if(x->right) {
		assert(x->value <= x->right->value);
		dfs(x->right);
	}
}

typedef vector<vector<int>> graph;

constexpr int MAX_X = 1000000000;
constexpr int MAX_N = 100000;
constexpr int MAX_LOG_N = 17;

RBST *root[MAX_N + 1];
int parent[MAX_LOG_N][MAX_N];
int depth[MAX_N];

void dfs(int v, int p, int d, const vector<int> &x, const graph &G) {
	parent[0][v] = p;
	depth[v] = d;

	const int pos = query(root[p], x[v]);
	root[v] = insert(root[p], pos, x[v]);

	for(const auto &u : G[v]) {
		if(u == p) continue;
		dfs(u, v, d + 1, x, G);
	}
}

void init(int r, int V, const vector<int> &x, const vector<vector<int>> &G) {
	dfs(r, V, 0, x, G);
	for(int k = 0; k + 1 < MAX_LOG_N; ++k) {
		for(int v = 0; v < V; ++v) {
			if(parent[k][v] < 0) parent[k + 1][v] = -1;
			else parent[k + 1][v] = parent[k][parent[k][v]];
		}
	}
}

int lca(int u, int v) {
	if(depth[u] > depth[v]) swap(u, v);
	for(int k = 0; k < MAX_LOG_N; ++k) {
		if(((depth[v] - depth[u]) >> k) & 1) {
			v = parent[k][v];
		}
	}

	if(u == v) return u;

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

	return parent[0][u];
}

int main() {
	cin.tie(nullptr);
	ios::sync_with_stdio(false);

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

	vector<int> x(n);
	for(auto &e : x) cin >> e;

	graph G(n);
	for(int i = 0; i < n - 1; ++i) {
		int a, b;
		cin >> a >> b;
		--a; --b;
		G[a].emplace_back(b);
		G[b].emplace_back(a);
	}

	init(0, n, x, G);

	while(q--) {
		int a, b, c;
		cin >> a >> b >> c;
		--a; --b;

		const int l = lca(a, b);
		const int p = parent[0][l];

		int L = 0, R = MAX_X;
		while(L + 1 < R) {
			const int M = (L + R) / 2;
			const int num = query(root[a], M) + query(root[b], M) - query(root[l], M) - query(root[p], M);

			if(c <= num) {
				R = M;
			}
			else {
				L = M;
			}
		}

		cout << R << '\n';
	}

	return EXIT_SUCCESS;
}

Measured memory_bytes: 163220