#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;
}