import std.stdio;
import std.typecons;
import std.algorithm;
import std.string;
import std.conv;
import std.datetime;
import std.algorithm;
import std.random;
import core.stdc.stdio;
import core.memory;
import core.bitop;
import core.stdc.stdlib;
import std.datetime;

class ArrayPool(T,int b){
	T[] pool;
	int idx;
	int size;
public:
	this(int s){
		size=s;
		pool = new T[b*size];
	}

	void Initialize(){
		idx=0;
		pool = new T[b*size];
	}

	T[] Get(){
		if(idx>=size){
			pool = new T[b*size];
			idx=0;
		}
		idx++;
		return pool[(idx-1)*b..idx*b];
	}
}

int LowerBoundIdx(T)(const T[] data,const ref T thre){
	int l=0;
	int r=cast(int)data.length+1;
	while(r-l>1){
		if(data[(l+r)/2-1] < thre) l = (l+r)/2;
		else r = (l+r)/2;
	}
	return l;
}

int UpperBoundIdx(T)(const T[] data,const ref T thre){
	int l=0;
	int r=cast(int)data.length+1;
	while(r-l>1){
		if(data[(l+r)/2-1] <= thre) l = (l+r)/2;
		else r = (l+r)/2;
	}
	return l;
}

class PersistentBPlusTree(T,int b){
	ArrayPool!(T,b) keyPool;
	ArrayPool!(Node,b+1) childPool;
	ArrayPool!(T,b+1) subPool;

	alias Tuple!(int,"count",T,"mVal") LEC;

	struct InsertResult{
		Node node;
		bool needSplit;
	}

	struct EraseResult{
		bool needMerge;
	}

	struct SplitResult{
		T top;
		Node node;
	}

	class Node{
	public:
		bool isLeaf = false;
		T[] keys;
		Node[] children;
		int[] subs;
		int keyCount = 0;
		int size = 0;
		int sum=0;
		void DebugOutput(){
			writeln("keyCount ",keyCount," size ",size);
			writeln("keys ",keys[0..keyCount]);
			writeln("children ",children[0..size]);
		}
		this(bool l){
			isLeaf = l;
			keys = keyPool.Get;
			if(!isLeaf)
				children = childPool.Get;
			subs = subPool.Get;
		}
		void Copy(const Node rhs){
			keyCount = rhs.keyCount;
			size = rhs.size;
			sum = rhs.sum;
			for(int i=0;i<keyCount;i++)
				keys[i] = rhs.keys[i];
			for(int i=0;i<size;i++)
				children[i] = cast(Node)rhs.children[i];
			for(int i=0;i<max(keyCount,size);i++)
				subs[i] = rhs.subs[i];
		}
		int Find(const ref T key) const{
			return UpperBoundIdx(keys[0..keyCount],key);
		}
		LEC LowerEqualCount(const ref T key) const{
			int f = UpperBoundIdx(keys[0..keyCount],key);
			int ret = 0;
			for(int i=0;i<f;i++){
				ret += subs[i];
			}
			if(f == 0)
				return LEC(0,T.min);
			else
				return LEC(ret,keys[f-1]);
		}
		T GetData(const ref T key) const{
			int f = LowerBoundIdx(keys[0..keyCount],key);
			return keys[f];
		}
		InsertResult InsertKey(T key){
			assert(isLeaf);
			Node nx = new Node(true);
			nx.Copy(this);
			return nx._InsertKey(key);
		}
		InsertResult _InsertKey(T key){
			assert(isLeaf);
			sum++;
			int f = Find(key);
			if(f>0 && keys[f-1] == key){
				subs[f-1]++;
				return InsertResult(this,false);
			}
			int s = 1;
			for(;f<keyCount;f++){
				swap(key,keys[f]);
				swap(s,subs[f]);
			}
			keys[keyCount] = key;
			subs[keyCount++] = s;
			return InsertResult(this,keyCount > b-1);
		}
		Node UpdateChild(int f,Node child){
			assert(!isLeaf);
			Node nx = new Node(false);
			nx.Copy(this);
			nx.children[f] = child;
			nx.sum += child.sum - nx.subs[f];
			nx.subs[f] = child.sum;
			return nx;
		}
		InsertResult InsertNode(int idx,T top,Node nd){
			assert(!isLeaf);
			sum += nd.sum;
			for(int ci = idx+1;ci<size;ci++){
				swap(children[ci],nd);
			}
			children[size++] = nd;
			for(int i=idx+1;i<size;i++){
				subs[i] = children[i].sum;
			}
			for(;idx<keyCount;idx++){
				swap(keys[idx],top);
			}
			keys[keyCount++] = top;
			return InsertResult(this,size > b);
		}
		SplitResult Split(){
			assert(size == b+1 || (isLeaf&&size==0));
			assert(keyCount == b);
			Node nx = new Node(isLeaf);
			if(isLeaf){
				keyCount = b/2;
				nx.keyCount = b-keyCount;
				nx.keys = keyPool.Get;
				nx.sum = 0;
				for(int i=keyCount;i<b;i++){
					nx.keys[i-keyCount] = keys[i];
					nx.subs[i-keyCount] = subs[i];
					nx.sum += subs[i];
				}
				sum -= nx.sum;
			}else{
				size = (b+1)/2;
				nx.size = b+1-size;
				nx.children = childPool.Get;
				nx.sum = 0;
				for(int i=size;i<b+1;i++){
					nx.children[i-size] = children[i];
					nx.subs[i-size] = subs[i];
					nx.sum += subs[i];
				}
				sum -= nx.sum;
				keyCount = size-1;
				nx.keyCount = nx.size-1;
				nx.keys = keyPool.Get;
				for(int i=keyCount+1;i<b;i++){
					nx.keys[i-keyCount-1] = keys[i];
				}
			}
			return SplitResult(keys[keyCount],nx);
		}
		Node SplitRoot(){
			SplitResult sr = Split;
			Node rt = new Node(false);
			rt.keys[0] = sr.top;
			rt.children[0] = this;
			rt.children[1] = sr.node;
			rt.subs[0] = sum;
			rt.subs[1] = sr.node.sum;
			rt.sum = rt.subs[0]+rt.subs[1];
			rt.size = 2;
			rt.keyCount = 1;
			return rt;
		}
	}

	Node root;

public:

	this(int s){
		keyPool = new ArrayPool!(T,b)(s/b);
		childPool = new ArrayPool!(Node,b+1)(s/b*2);
		subPool = new ArrayPool!(int,b+1)(s/b);
		c = new Cource[128];
		root = new Node(true);
		root.keys = keyPool.Get;
		root.size = 0;
	}

	this(PersistentBPlusTree rhs,Node rt){
		keyPool = rhs.keyPool;
		childPool = rhs.childPool;
		c = rhs.c;
		root = rt;
	}

	LEC LowerEqualCount(T key){
		int ret=0;
		Node now = root;
		while(!now.isLeaf){
			int f = now.Find(key);
			for(int i=0;i<f;i++)
				ret += now.subs[i];
			now = now.children[f];
		}
		LEC l = now.LowerEqualCount(key);
		l.count += ret;
		return l;
	}

	alias Tuple!(Node,"p",int,"idx") Cource;
	Cource[] c;
	PersistentBPlusTree Insert(T key){
		int s = 0;
		Node now = root;
		while(!now.isLeaf){
			int f = now.Find(key);
			c[s++] = Cource(now,f);
			now = now.children[f];
		}
		InsertResult ir = now.InsertKey(key);
		now = ir.node;
		while(s>0){
			now = c[--s].p;
			int f = c[s].idx;
			SplitResult sr;
			if(ir.needSplit){
				sr = ir.node.Split;
			}
			now = now.UpdateChild(f,ir.node);
			if(ir.needSplit){
				ir = now.InsertNode(f,sr.top,sr.node);
			}
			ir.node = now;
		}
		Node rt = now;
		if(ir.needSplit){
			rt = now.SplitRoot;
		}
		return new PersistentBPlusTree(this,rt);
	}

	void DebugOutput() const{
		alias Tuple!(int,"depth",int,"idx",int,"parent",const Node,"node") dbg;
		dbg[] queue;
		queue.reserve(1024);
		int zi=0;
		queue ~= dbg(0,zi++,-1,root);
		int o=0;
		while(o<queue.length){
			int d=queue[o].depth;
			int i=queue[o].idx;
			int p=queue[o].parent;
			const Node nd=queue[o].node;
			writeln("Depth ",d," Idx ",i," Parent ",p," Keys ",nd.keys[0..nd.keyCount]," subs ",nd.subs[0..max(nd.keyCount,nd.size)]);
			if(!(nd.children is null)){
				foreach(nx;nd.children[0..nd.size]){
					queue ~= dbg(d+1,zi++,i,nx);
				}
			}
			o++;
		}
	}
}

alias Tuple!(int,"dep",int,"idx") di;
di[] euler;
int[] invEuler;
int ec=0;

class SparseTable{
	di[][] data;
	this(di[] d){
		int h = d.length.bsr+1;
		data = new di[][](h,d.length);
		for(int i=0;i<d.length;i++) data[0][i] = d[i];
		for(int k=1;k<h;k++) for(int i=0;i<=d.length-(1<<k);i++) data[k][i] = min(data[k-1][i],data[k-1][i+(1<<(k-1))]);
	}
	di Get(int begin,int end){
		int h = (end-begin).bsr;
		return min(data[h][begin],data[h][end-(1<<h)]);
	}
}

class LCA{
	SparseTable sp;
	this(){
		sp = new SparseTable(euler);
	}
	int Get(int a,int b){
		a = invEuler[a];
		b = invEuler[b];
		if(a>b)
			swap(a,b);
		return sp.Get(a,b+1).idx;
	}
}

alias PersistentBPlusTree!(int,32) pbpt;
int[][] graph;
pbpt[] tree;
int[] val;
int[] parents;

void DFS(int idx,int p,pbpt t,int depth){
	parents[idx] = p;
	invEuler[idx] = ec;
	euler[ec++] = di(depth,idx);
	tree[idx] = t.Insert(val[idx]);
	foreach(c;graph[idx]){
		if(c!=p){
			DFS(c,idx,tree[idx],depth+1);
			euler[ec++] = di(depth,idx);
		}
	}
}

alias Tuple!(int,"count",int,"mVal") tmpLEC;
tmpLEC LowerEqualCount(int[] d,int key){
	tmpLEC ret = tmpLEC(0,int.min);
	foreach(t;d){
		if(t<=key){
			ret.count++;
			ret.mVal = max(ret.mVal,t);
		}
	}
	return ret;
}

void main(){
	auto sTime = MonoTime.currTime;
	int n,q;
	scanf("%d%d",&n,&q);
	val = new int[n];
	graph = new int[][n];
	tree = new pbpt[n];
	euler = new di[n*2-1];
	invEuler = new int[n];
	parents = new int[n];
	parents[0] = -1;
	int minVal = int.max;
	int maxVal = int.min;
	for(int i=0;i<n;i++){
		scanf("%d",&val[i]);
		minVal = min(minVal,val[i]);
		maxVal = max(maxVal,val[i]);
	}
	for(int i=0;i<n-1;i++){
		int a,b;
		scanf("%d%d",&a,&b);
		graph[--a] ~= --b;
		graph[b] ~= a;
	}
	DFS(0,-1,new pbpt(100000),0);


	LCA lca = new LCA;

	auto dur = MonoTime.currTime-sTime;
	if(dur.total!"msecs">=2000)
		"WA".writeln;

	for(int i=0;i<q;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		a--;
		b--;
		int anc = lca.Get(a,b);
		int ap = parents[anc];
		int l = minVal;
		int r = maxVal+1;
		while(r-l>1){
			int m = (r+l)/2-1;
			int sum = 0;
			int t=int.min;
			auto lec = tree[a].LowerEqualCount(m);
			sum += lec.count;
			t = max(t,lec.mVal);

			lec = tree[b].LowerEqualCount(m);
			sum += lec.count;

			t = max(t,lec.mVal);
			lec = tree[anc].LowerEqualCount(m);
			sum -= lec.count;
			t = max(t,lec.mVal);
			if(ap !=-1){
				lec = tree[ap].LowerEqualCount(m);
				sum -= lec.count;
				t = max(t,lec.mVal);
			}
			if(sum < c){
				l = m+1;
			}else{
				r = m+1;
			}
		}
		int s = tree[a].LowerEqualCount(l).mVal;
		s = max(s,tree[b].LowerEqualCount(l).mVal);
		s = max(s,tree[anc].LowerEqualCount(l).mVal);
		if(ap != -1){
			s = max(s,tree[ap].LowerEqualCount(l).mVal);
		}
		printf("%d\n",s);
	}
}