package main
import (
"io"
"os"
"strconv"
"time"
)
const LOG = 20
type Node struct {
l int32
r int32
h uint64
}
var data []byte
var ptr int
var nodes []Node
var tot int32
func nextInt() int {
n := len(data)
for ptr < n && (data[ptr] < '0' || data[ptr] > '9') {
ptr++
}
v := 0
for ptr < n && data[ptr] >= '0' && data[ptr] <= '9' {
v = v*10 + int(data[ptr]-'0')
ptr++
}
return v
}
func splitmix64(x uint64) uint64 {
x += 0x9e3779b97f4a7c15
x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9
x = (x ^ (x >> 27)) * 0x94d049bb133111eb
return x ^ (x >> 31)
}
func update(prev int32, l, r, pos int, hv uint64) int32 {
idx := tot
tot++
nodes[idx] = nodes[prev]
if l == r {
nodes[idx].h ^= hv
return idx
}
mid := (l + r) >> 1
if pos <= mid {
nodes[idx].l = update(nodes[prev].l, l, mid, pos, hv)
} else {
nodes[idx].r = update(nodes[prev].r, mid+1, r, pos, hv)
}
nodes[idx].h = nodes[nodes[idx].l].h ^ nodes[nodes[idx].r].h
return idx
}
func findAny(a, b, c, d int32, l, r, ql, qr int) int {
if qr < l || r < ql {
return -1
}
h := nodes[a].h ^ nodes[b].h ^ nodes[c].h ^ nodes[d].h
if h == 0 {
return -1
}
if l == r {
return l
}
mid := (l + r) >> 1
if ql <= mid {
res := findAny(nodes[a].l, nodes[b].l, nodes[c].l, nodes[d].l, l, mid, ql, qr)
if res != -1 {
return res
}
}
if qr > mid {
res := findAny(nodes[a].r, nodes[b].r, nodes[c].r, nodes[d].r, mid+1, r, ql, qr)
if res != -1 {
return res
}
}
return -1
}
func lca(u, v int, up []int32, depth []int, stride int) int {
if depth[u] < depth[v] {
u, v = v, u
}
d := depth[u] - depth[v]
k := 0
for d > 0 {
if d&1 != 0 {
u = int(up[k*stride+u])
}
d >>= 1
k++
}
if u == v {
return u
}
for k = LOG - 1; k >= 0; k-- {
pu := int(up[k*stride+u])
pv := int(up[k*stride+v])
if pu != pv {
u = pu
v = pv
}
}
return int(up[u])
}
func main() {
data, _ = io.ReadAll(os.Stdin)
n := nextInt()
q := nextInt()
val := make([]int, n+1)
for i := 1; i <= n; i++ {
val[i] = nextInt()
}
head := make([]int32, n+1)
for i := 0; i <= n; i++ {
head[i] = -1
}
to := make([]int32, 2*(n-1))
nxt := make([]int32, 2*(n-1))
var ec int32
for i := 0; i < n-1; i++ {
x := nextInt()
y := nextInt()
to[ec] = int32(y)
nxt[ec] = head[x]
head[x] = ec
ec++
to[ec] = int32(x)
nxt[ec] = head[y]
head[y] = ec
ec++
}
hashv := make([]uint64, n+1)
seed := uint64(time.Now().UnixNano())
for i := 1; i <= n; i++ {
h := splitmix64(seed + uint64(i))
if h == 0 {
h = 1
}
hashv[i] = h
}
maxNodes := (n + 5) * 21
nodes = make([]Node, maxNodes)
tot = 1
roots := make([]int32, n+1)
depth := make([]int, n+1)
stride := n + 1
up := make([]int32, LOG*stride)
roots[1] = update(0, 1, n, val[1], hashv[val[1]])
stack := make([]int, 0, n)
stack = append(stack, 1)
for len(stack) > 0 {
v := stack[len(stack)-1]
stack = stack[:len(stack)-1]
for e := head[v]; e != -1; e = nxt[e] {
u := int(to[e])
if u == int(up[v]) {
continue
}
up[u] = int32(v)
depth[u] = depth[v] + 1
roots[u] = update(roots[v], 1, n, val[u], hashv[val[u]])
stack = append(stack, u)
}
}
for k := 1; k < LOG; k++ {
base := k * stride
prev := (k - 1) * stride
for v := 1; v <= n; v++ {
p := up[prev+v]
if p != 0 {
up[base+v] = up[prev+int(p)]
}
}
}
out := make([]byte, 0, q*8)
for i := 0; i < q; i++ {
u := nextInt()
v := nextInt()
l := nextInt()
r := nextInt()
w := lca(u, v, up, depth, stride)
pw := int(up[w])
ans := findAny(roots[u], roots[v], roots[w], roots[pw], 1, n, l, r)
out = strconv.AppendInt(out, int64(ans), 10)
out = append(out, '\n')
}
os.Stdout.Write(out)
}