选数异或 蓝桥杯

选数异或

题意:

给定数组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;
}

posted @ 2022-10-26 20:21  wzx_believer  阅读(93)  评论(0编辑  收藏  举报