# [蓝桥杯 2022 省 A] 选数异或
## 题目描述
给定一个长度为 $n$ 的数列 $A_{1}, A_{2}, \cdots, A_{n}$ 和一个非负整数 $x$, 给定 $m$ 次查询, 每次询问能否从某个区间 $[l, r]$ 中选择两个数使得他们的异或等于 $x$ 。
## 输入格式
输入的第一行包含三个整数 $n, m, x$ 。
第二行包含 $n$ 个整数 $A_{1}, A_{2}, \cdots, A_{n}$。
接下来 $m$ 行,每行包含两个整数 $l_{i}, r_{i}$ 表示询问区间 $\left[l_{i}, r_{i}\right]$ 。
## 输出格式
对于每个询问, 如果该区间内存在两个数的异或为 $x$ 则输出 `yes`, 否则输出 `no`。
## 样例 #1
### 样例输入 #1
```
4 4 1
1 2 3 4
1 4
1 2
2 3
3 3
```
### 样例输出 #1
```
yes
no
yes
no
```
## 提示
**【样例说明】**
显然整个数列中只有 2,3 的异或为 1 。
**【评测用例规模与约定】**
对于 $20 \%$ 的评测用例, $1 \leq n, m \leq 100$;
对于 $40 \%$ 的评测用例, $1 \leq n, m \leq 1000$;
对于所有评测用例, $1 \leq n, m \leq 10^5,0 \leq x<2^{20}, 1 \leq l_{i} \leq r_{i} \leq n$ , $0 \leq A_{i}<2^{20}$ 。
蓝桥杯 2022 省赛 A 组 D 题。
第一眼看到异或我以为是Trie树,但是发现查询好麻烦。后来看了y总的视频发现可以进行转化,首先a ^ b = x 可以变成 a = b ^ x,对于每一个a[i],找到左边离他最近的一个满足条件的b的下标,记为g(i)且g(i) < i ,在后面每一次查询的时候只需要判断区间的某个i是否存在g(i)大于l即可。
又因为满足条件的g(i)一定是大于l的,所以只要小于l肯定没解,所以可以把范围扩大到1-r中是否存在满足条件的解。
接下来就是代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1000010, M = (1 << 20) + 10;
int last[M], g[N];
int n, m, x;
int main(void)
{
cin >> n >> m >> x;
for(int i=1 ; i<=n ; i++)
{
int a;
cin >> a;
g[i] = max(g[i-1], last[a ^ x]); // 区间中满足 a ^ b = x的最大下标
last[a] = i; //更新a出现的最后的下标
}
while(m --)
{
int l, r;
cin >> l >> r;
if(g[r] >= l) puts("yes");
else puts("no");
}
return 0;
}