选数异或 蓝桥杯
选数异或
题意:
给定数组a 和整数x ,m 次询问,每次询问区间[ l , r ] 是否存在两个数字使得异或值等于x
分析:
一个比较经典的解法
对每个数字a [ i ] ,找到它左边最近的a [ j ] ,满足a [ i ] ⊕ a [ j ] = x,则< j , i > 二元组是一个合法解,其中j < i。
用线段是维护区间最大值即可
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100000 + 10;
int tree[maxn << 2];
int Left[maxn], pos[(1 << 20) + 10];
int a[maxn], n, m, x;
//线段树模板
void build(int o, int l, int r)
{
if(l == r)
{
tree[o] = Left[l];
return;
}
int mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
tree[o] = max(tree[o << 1], tree[o << 1 | 1]);
}
int query(int o, int l, int r, int L, int R)
{
if(L <= l && r <= R)return tree[o];
int mid = (l + r) >> 1;
int ans = 0;
if(L <= mid)ans = max(ans, query(o << 1, l, mid, L, R));
if(R > mid)ans = max(ans, query(o << 1 | 1, mid + 1, r, L, R));
return ans;
}
int main()
{
scanf("%d%d%d", &n, &m, &x);
for(int i = 1; i <= n; i++) //预处理Left数组
{
scanf("%d", &a[i]);
Left[i] = pos[a[i] ^ x];
pos[a[i]] = i;
}
build(1, 1, n);//线段树建树
while(m--)
{
int l, r;
scanf("%d%d", &l, &r);
if(query(1, 1, n, l, r) >= l)//查询区间最值
printf("yes\n");
else
printf("no\n");
}
return 0;
}