#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <limits>
#include <memory>
#include <queue>
#include <stack>
#include <utility>
#include <vector>
namespace lc {
struct Edge {
	int to;
	Edge() : to(0) { }
	explicit Edge(int to) : to(to) { }
};
}
namespace lc {
template <typename EdgeType>
class AdjacencyList {
public:
	typedef std::vector<EdgeType> ListType;
private:
	std::vector<ListType> m_lists;
public:
	explicit AdjacencyList(int n = 0)
		: m_lists(n)
	{ }
	int size() const { return m_lists.size(); }
	template <typename... Args>
	void add_edge(int u, Args&&... args){
		m_lists[u].emplace_back(args...);
	}
	const ListType &operator[](int u) const { return m_lists[u]; }
};
}
namespace lc {
template <typename EdgeType>
std::vector<int> topological_sort(const AdjacencyList<EdgeType> &graph){
	const int n = graph.size();
	std::vector<int> in_degrees(n);
	for(int u = 0; u < n; ++u){
		for(const auto &e : graph[u]){ ++in_degrees[e.to]; }
	}
	std::queue<int> q;
	for(int u = 0; u < n; ++u){
		if(in_degrees[u] == 0){ q.push(u); }
	}
	std::vector<int> result;
	while(!q.empty()){
		const int u = q.front();
		q.pop();
		result.push_back(u);
		for(const auto &e : graph[u]){
			if(--in_degrees[e.to] == 0){ q.push(e.to); }
		}
	}
	if(static_cast<int>(result.size()) != n){ return std::vector<int>(); }
	return result;
}
}
namespace lc {
class LowestCommonAncestor {
private:
	std::vector<int> m_depth_table;
	std::vector<std::vector<int>> m_skip_table;
	template <class EdgeType>
	void build_tables(
		int u, std::vector<int> &s, const AdjacencyList<EdgeType> &graph)
	{
		if(m_depth_table[u] >= 0){ return; }
		const int d = s.size(), m = m_skip_table.size();
		for(int i = 0, j = 1; i < m && j <= d; ++i, j += j){
			m_skip_table[u][i] = s[d - j];
		}
		m_depth_table[u] = d;
		s.push_back(u);
		for(size_t i = 0; i < graph[u].size(); ++i){
			build_tables(graph[u][i].to, s, graph);
		}
		s.pop_back();
	}
public:
	LowestCommonAncestor() : m_depth_table(), m_skip_table() { }
	template <class EdgeType>
	LowestCommonAncestor(
		int root, const AdjacencyList<EdgeType> &graph)
		: m_depth_table(graph.size(), -1)
		, m_skip_table(
			graph.size(),
			std::vector<int>(32 - __builtin_clz(graph.size()), -1))
	{
		std::vector<int> s;
		build_tables(root, s, graph);
	}
	int query(int a, int b) const {
		const int m = m_skip_table[0].size();
		if(m_depth_table[a] < m_depth_table[b]){ std::swap(a, b); }
		for(int i = m - 1; i >= 0; --i){
			if(m_depth_table[a] - (1 << i) >= m_depth_table[b]){
				a = m_skip_table[a][i];
			}
		}
		if(a == b){ return a; }
		for(int i = m - 1; i >= 0; --i){
			if(m_skip_table[a][i] != m_skip_table[b][i]){
				a = m_skip_table[a][i];
				b = m_skip_table[b][i];
			}
		}
		return m_skip_table[a][0];
	}
	int get_parent(int v) const {
		return m_skip_table[v][0];
	}
};
}
namespace lc {
template <class T>
class FixedMemoryPool {
private:
	static const size_t BLOCK_SIZE = (1 << 18);
	std::vector<T *> m_blocks;
	std::stack<T *> m_pool;
	FixedMemoryPool() = default;
	FixedMemoryPool(const FixedMemoryPool<T> &) = delete;
public:
	static FixedMemoryPool<T> &instance(){
		static FixedMemoryPool<T> self;
		return self;
	}
	~FixedMemoryPool(){
		for(T *p : m_blocks){ free(p); }
	}
	T *allocate(){
		if(m_pool.empty()){
			T *block = static_cast<T *>(malloc(sizeof(T) * BLOCK_SIZE));
			for(size_t i = 0; i < BLOCK_SIZE; ++i){
				m_pool.push(block + i);
			}
		}
		T *p = m_pool.top();
		m_pool.pop();
		return p;
	}
	void deallocate(T *p){ m_pool.push(p); }
};
template <class T>
class PoolAllocator {
public:
	typedef size_t size_type;
	typedef ptrdiff_t difference_type;
	typedef T *pointer;
	typedef const T *const_pointer;
	typedef T &reference;
	typedef const T &const_reference;
	typedef T value_type;
	template <class U>
	struct rebind {
		typedef PoolAllocator<U> other;
	};
	PoolAllocator(){ }
	template <class U>
	PoolAllocator(const PoolAllocator<U> &){ }
	pointer allocate(size_type n, const void *hint = 0){
		return FixedMemoryPool<T>::instance().allocate();
	}
	void deallocate(pointer p, size_type){
		FixedMemoryPool<T>::instance().deallocate(p);
	}
	template <class U, class... Args>
	void construct(U *p, Args&&... args){
		new(static_cast<void *>(p)) T(std::forward<Args>(args)...);
	}
	template <class U> void destroy(U *p){ p->~U(); }
};
}
namespace lc {
template <class Traits>
class PersistentRBSTList {
public:
	typedef PersistentRBSTList<Traits> self_type;
	typedef typename Traits::value_type value_type;
protected:
	struct node_type {
		value_type value;
		value_type cache;
		size_t size;
		std::shared_ptr<node_type> children[2];
	};
	typedef std::shared_ptr<node_type> node_ptr;
	typedef PoolAllocator<node_type> allocator_type;
	Traits m_traits;
	node_ptr m_root;
	void initialize_node(node_ptr &p, const value_type &v) const {
		p->value = p->cache = v;
		p->size = 1;
		p->children[0] = p->children[1] = node_ptr();
	}
	node_ptr copy_node(const node_ptr &p) const {
		return std::allocate_shared<node_type>(allocator_type(), *p);
	}
	size_t size(const node_ptr &p) const {
		if(!p){ return 0; }
		return p->size;
	}
	node_ptr kth(const node_ptr &p, size_t k) const {
		if(k >= size(p)){ return node_ptr(); }
		const size_t ls = size(p->children[0]);
		if(k == ls){
			return p;
		}else if(k < ls){
			return kth(p->children[0], k);
		}else{
			return kth(p->children[1], k - 1 - ls);
		}
	}
	node_ptr refresh(node_ptr &p) const {
		if(!p){ return node_ptr(); }
		p->cache = p->value;
		if(p->children[0]){
			p->cache = m_traits(p->children[0]->cache, p->cache);
		}
		if(p->children[1]){
			p->cache = m_traits(p->cache, p->children[1]->cache);
		}
		p->size = 1 + size(p->children[0]) + size(p->children[1]);
		return p;
	}
	node_ptr update(const node_ptr &t, size_t k, const value_type &v) const {
		if(!t){ return node_ptr(); }
		const size_t ls = size(t->children[0]);
		node_ptr p = copy_node(t);
		if(k == ls){
			p->value = v;
		}else if(k < ls){
			p->children[0] = update(p->children[0], k, v);
		}else{
			p->children[1] = update(p->children[1], k - ls - 1, v);
		}
		return refresh(p);
	}
	template <class Iterator>
	std::pair<node_ptr, Iterator> range_copy(
		Iterator first, Iterator last, int depth) const
	{
		if(depth == 0){ return std::make_pair(node_ptr(), first); }
		const auto l = range_copy(first, last, depth - 1);
		first = l.second;
		if(first == last){ return l; }
		node_ptr c = std::allocate_shared<node_type>(allocator_type());
		initialize_node(c, *(first++));
		c->children[0] = l.first;
		const auto r = range_copy(first, last, depth - 1);
		c->children[1] = r.first;
		return std::make_pair(refresh(c), r.second);
	}
	PersistentRBSTList(node_ptr root, const Traits &traits)
		: m_traits(traits)
		, m_root(root)
	{ }
public:
	explicit PersistentRBSTList(const Traits &traits = Traits())
		: m_traits(traits)
		, m_root()
	{ }
	template <class Iterator>
	PersistentRBSTList(
		Iterator first, Iterator last, const Traits &traits = Traits())
		: m_traits(traits)
		, m_root()
	{
		const int n = std::distance(first, last);
		const int depth = (n == 0 ? 0 : (32 - __builtin_clz(n)));
		m_root = range_copy(first, last, depth).first;
	}
	PersistentRBSTList(const self_type &x)
		: m_traits(x.m_traits)
		, m_root(x.m_root)
	{ }
	const value_type &operator[](size_t k) const {
		return kth(m_root, k)->value;
	}
	self_type update(size_t k, const value_type &x) const {
		return self_type(update(m_root, k, x), m_traits);
	}
};
}
namespace lc {
template <class T>
struct SumTraits {
	typedef T value_type;
	value_type operator()(const value_type &a, const value_type &b) const {
		return a + b;
	}
};
}
namespace lc {
template <class T>
class CoordinateCompressor {
private:
	std::vector<T> m_coords;
public:
	CoordinateCompressor() : m_coords() { }
	template <class Iterator>
	CoordinateCompressor(Iterator first, Iterator last)
		: m_coords(first, last)
	{
		build();
	}
	size_t build(){
		sort(m_coords.begin(), m_coords.end());
		m_coords.erase(
			unique(m_coords.begin(), m_coords.end()), m_coords.end());
		return m_coords.size();
	}
	size_t compress(const T &x) const {
		return std::lower_bound(
			m_coords.begin(), m_coords.end(), x) - m_coords.begin();
	}
	const T &decompress(const size_t x) const {
		return m_coords[x];
	}
	size_t size() const {
		return m_coords.size();
	}
};
}
using namespace std;
class PersistentList : public lc::PersistentRBSTList<lc::SumTraits<int>> {
private:
	int cache(const node_ptr &p) const {
		if(!p){ return 0; }
		return p->cache;
	}
public:
	PersistentList()
		: lc::PersistentRBSTList<lc::SumTraits<int>>()
	{ }
	PersistentList(const PersistentList &p)
		: lc::PersistentRBSTList<lc::SumTraits<int>>(p)
	{ }
	PersistentList(const lc::PersistentRBSTList<lc::SumTraits<int>> &p)
		: lc::PersistentRBSTList<lc::SumTraits<int>>(p)
	{ }
	template <class Iterator>
	PersistentList(Iterator first, Iterator last)
		: lc::PersistentRBSTList<lc::SumTraits<int>>(first, last)
	{ }
	int solve(
		const PersistentList &a, const PersistentList &b,
		const PersistentList &p, int k) const
	{
		node_ptr cur_a = a.m_root, cur_b = b.m_root;
		node_ptr cur_c = m_root, cur_p = p.m_root;
		int answer = 0;
		while(true){
			const int la = cache(cur_a->children[0]);
			const int lb = cache(cur_b->children[0]);
			const int lc = cache(cur_c->children[0]);
			const int lp = cache(cur_p->children[0]);
			const int lsum = la + lb - lc - lp;
			if(k < lsum){
				cur_a = cur_a->children[0];
				cur_b = cur_b->children[0];
				cur_c = cur_c->children[0];
				cur_p = cur_p->children[0];
				continue;
			}else{
				answer += size(cur_a->children[0]);
				k -= lsum;
			}
			const int csum =
				cur_a->value + cur_b->value - cur_c->value - cur_p->value;
			if(k < csum){
				return answer;
			}else{
				cur_a = cur_a->children[1];
				cur_b = cur_b->children[1];
				cur_c = cur_c->children[1];
				cur_p = cur_p->children[1];
				k -= csum;
				answer += 1;
			}
		}
		return -1;
	}
};
typedef lc::Edge Edge;
typedef lc::AdjacencyList<Edge> Graph;
int main(){
	int n, q;
	cin >> n >> q;
	vector<int> x(n);
	for(int i = 0; i < n; ++i){ cin >> x[i]; }
	lc::CoordinateCompressor<int> comp(x.begin(), x.end());
	const int m = comp.size();
	for(int i = 0; i < n; ++i){ x[i] = comp.compress(x[i]); }
	Graph conn(n);
	for(int i = 1; i < n; ++i){
		int a, b;
		cin >> a >> b;
		--a; --b;
		conn.add_edge(a, b);
		conn.add_edge(b, a);
	}
	lc::LowestCommonAncestor lca(0, conn);
	Graph tree(n);
	for(int i = 1; i < n; ++i){
		const int p = lca.get_parent(i);
		tree.add_edge(p, i);
	}
	const vector<int> topo = lc::topological_sort(tree);
	vector<int> init(m, 0);
	PersistentList init_list(init.begin(), init.end());
	vector<PersistentList> lists(n);
	lists[0] = init_list;
	for(int i = 0; i < n; ++i){
		const int u = topo[i];
		if(i != 0){ lists[u] = lists[lca.get_parent(u)]; }
		lists[u] = lists[u].update(x[u], lists[u][x[u]] + 1);
	}
	for(int i = 0; i < q; ++i){
		int a, b, l;
		cin >> a >> b >> l;
		--a; --b; --l;
		const int c = lca.query(a, b);
		const int p = lca.get_parent(c);
		const int answer = lists[c].solve(
			lists[a], lists[b], p < 0 ? init_list : lists[p], l);
		cout << comp.decompress(answer) << endl;
	}
	return 0;
}

Measured memory_bytes: 175132