P8773 选数异或(异或运算+st表)

P8773 选数异或(异或运算+st表)

题目传送门

题意简介

给定一个序列及 \(x\) ,多次询问 \([L,R]\) 区间内是否存在两个数异或值为 \(x\)

思路

预处理出 \(ans\) 数组,其中 \(a_i\) \(\oplus\) \(a_{ans_i}\) \(=\) \(x\)\(ans_i\)\(a_{ans_i}\) 这个值在 \(i\) 位置左侧最后一次出现的位置,由异或运算的性质知 \(a_{ans_i}\) \(=\) \(a_i\) \(\oplus\) \(x\),遍历序列时对于每一个 \(i\),将 \(a_i \oplus x\) 这个值最后一次出现的位置作为 \(ans_i\) 的值
对于每一次询问的区间,找出 \(ans_{L \sim R}\) 中的最大值,若该值在询问区间内出现则成立,考虑使用st表维护区间最值

Code

#include<iostream>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=1e5+5;
const int LogN=20;
const int MAXN=(1<<20)+5;
int n,m,x,a[N],Log[N],last[MAXN],dp[N],st[N][LogN];
int main()
{
    IOS;
    cin>>n>>m>>x;
    Log[0]=-1;
    for(int i=1;i<=n;i++)
        cin>>a[i],dp[i]=last[a[i]^x],last[a[i]]=i,Log[i]=Log[i>>1]+1;
    for(int i=1;i<=n;i++)
        st[i][0]=dp[i];
    for(int j=1;j<=Log[n];j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
    while(m--)
    {
        int L,R,k,ans;
        cin>>L>>R,k=Log[R-L+1];
        ans=max(st[L][k],st[R-(1<<k)+1][k]);
        if(ans>=L)
            cout<<"yes"<<'\n';
        else
            cout<<"no"<<'\n';
    }
    return 0;
}

完结撒花~

posted @ 2025-07-30 17:02  FallingGardenia  阅读(8)  评论(0)    收藏  举报