#include<iostream>   // 引入输入输出流库
#include<vector>     // 引入向量容器库(虽然本代码未直接使用vector存储数据,但保留标准结构)
using namespace std;  // 使用标准命名空间,避免每次调用std库函数时加前缀
#define ll long long  // 宏定义:将ll替换为long long,简化长整型声明
#define int long long // 宏定义:将int替换为long long,确保所有int类型都是长整型,避免溢出
struct Node{               // 定义字典树节点结构体
    int ch[2];  // 存储两个子节点的索引(0和1,对应二进制位的两种可能)
    int siz;    // 记录当前节点在该版本中的大小(用于判断区间内是否存在有效路径)
};
// 常量定义
const int maxn = 2e5 + 10;    // 最大数据量(n的上限)
const int maxnode = maxn * 32; // 最大节点数(每个数有32位,预估足够存储所有节点)
Node tree[maxnode];  // 存储所有字典树节点的数组(全局存储,避免动态分配开销)
int root[maxn];      // 存储每个版本的根节点索引(root[i]表示插入前i个元素后的字典树根)
int idx = 0;         // 节点计数器(用于分配新节点的唯一索引)
// 插入操作:在旧版本基础上创建新版本,插入值v
// 参数:x-旧版本根节点索引;y-新版本根节点的引用(用于存储新根索引);v-要插入的值
void insert(int x, int &y, int v) {
    y = ++idx;  // 创建新版本的根节点(idx自增,确保唯一索引)
    int curr = y;  // curr指向当前正在处理的新节点(从新根开始)
    // 从最高位(30位)到最低位(0位)处理v的每个二进制位
    // (30位足够覆盖1e9范围内的数,2^30约为1e9)
    for(int i = 30; i >= 0; i--) {
        int j = (v >> i) & 1;  // 提取v的第i位(0或1)
        // 复制旧版本中与当前位不同的子节点(!j),实现"复用未修改的路径"
        tree[curr].ch[!j] = tree[x].ch[!j];
        // 为当前位(j)创建新的子节点(因为当前位需要修改)
        tree[curr].ch[j] = ++idx;
        // 更新指针:旧版本指针移动到对应子节点,当前新版本指针移动到新创建的子节点
        x = tree[x].ch[j];       // x指向旧版本中j位对应的子节点(可能为0,即不存在)
        curr = tree[curr].ch[j]; // curr指向新版本中j位对应的新子节点
        // 设置新子节点的大小:如果旧节点存在,新节点大小=旧节点大小+1(继承+新增);否则为1(全新节点)
        tree[curr].siz = (x == 0) ? 1 : tree[x].siz + 1;
    }
}
// 查询操作:在区间[l, r]对应的版本中,查询与v异或的最大值
// 参数:x-版本l-1的根节点(表示前l-1个元素);y-版本r的根节点(表示前r个元素);v-查询值
int query(int x, int y, int v) {
    int ans = 0;  // 存储异或最大值的结果
    // 从最高位到最低位遍历,优先选择能使异或结果更大的路径
    for(int i = 30; i >= 0; i--) {
        int j = (v >> i) & 1;  // 提取v的第i位(0或1)
        // 尝试选择与当前位相反的路径(!j):若y中该路径的节点数 > x中该路径的节点数,
        // 说明区间[l, r]内存在足够的数,使得该位异或结果为1(最大化结果)
        if(tree[y].ch[!j] && tree[tree[y].ch[!j]].siz > tree[tree[x].ch[!j]].siz) {
            x = tree[x].ch[!j];  // x移动到旧版本中!j对应的子节点
            y = tree[y].ch[!j];  // y移动到新版本中!j对应的子节点
            ans += (1 << i);     // 该位异或结果为1,累加2^i到答案
        } else {
            // 若相反路径不可行,选择相同的路径(j),该位异或结果为0
            x = tree[x].ch[j];
            y = tree[y].ch[j];
        }
    }
    return ans;  // 返回最大异或值
}
signed main() {  // 使用signed main(因#define int long long,避免返回值类型冲突)
    // 关闭输入输出流同步,加速cin/cout(代价是不能混用printf/scanf)
    ios::sync_with_stdio(false);
    cin.tie(0);  // 解除cin与cout的绑定,进一步加速
    cout.tie(0);
    int t;  // 测试用例数量
    cin >> t;
    while(t--) {  // 循环处理每个测试用例
        int n, q;  // n-元素数量;q-查询数量
        cin >> n >> q;
        idx = 0;  // 重置节点计数器(每个测试用例独立)
        root[0] = ++idx;  // 初始化版本0的根节点(空树)
        // 初始化根节点的子节点和大小(空树状态)
        tree[root[0]].ch[0] = tree[root[0]].ch[1] = 0;
        tree[root[0]].siz = 0;
        // 插入n个元素,构建n个版本的字典树
        for(int i = 1; i <= n; i++) {
            int x;  // 当前要插入的元素
            cin >> x;
            // 基于版本i-1创建版本i,插入x(root[i]为新版本根)
            insert(root[i-1], root[i], x);
        }
        // 处理q次查询
        while(q--) {
            int l, r, x;  // l-左边界;r-右边界;x-查询值
            cin >> l >> r >> x;
            // 检查区间合法性(越界则输出0)
            if(l < 1 || r > n || l > r) {
                cout << 0 << '\n';
                continue;
            }
            // 查询区间[l, r](即版本r与版本l-1的差集)中与x异或的最大值
            cout << query(root[l-1], root[r], x) << '\n';
        }
    }
    return 0;
}