题目大意
给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X (L <= R)。求A[L] 至 A[R] 这R - L + 1个数中,与X 进行异或运算(Xor),得到的最大值是多少?
Input
第1行:2个数N, Q中间用空格分隔,分别表示数组的长度及查询的数量(1 <= N <= 50000, 1 <= Q <= 50000)。
第2 - N+1行:每行1个数,对应数组A的元素(0 <= A[i] <= 10^9)。
第N+2 - N+Q+1行:每行3个数X, L, R,中间用空格分隔。(0 <= X <= 10^9,0 <= L <= R < N)
Output
输出共Q行,对应数组A的区间[L,R]中的数与X进行异或运算,所能得到的最大值。
分析
这类求xor最大的题,一般考虑从高位开始贪心,尽量找该位不同的数,然后一位位往下做。
题目只有区间查询,于是可以先建一个可持久化Trie。然后?对于每个询问,就这样从高位开始在Trie上往下走,求出一个最大答案。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=50005,maxm=1550005,Log=30;
int tot,n,q,son[maxm][2],sum[maxm],root[maxn];
bool bz[Log+5];
char c;
int read()
{
int x=0;
for (c=getchar();c<'0' || c>'9';c=getchar());
for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48;
return x;
}
void insert(int v,int &x,int y)
{
x=++tot;
memcpy(son[x],son[y],8);
sum[x]=sum[y]+1;
if (!v) return;
insert(v-1,son[x][bz[v-1]],son[y][bz[v-1]]);
}
int find(int v,int x,int y)
{
if (!v) return 0;
if (sum[son[x][bz[v-1]]]>sum[son[y][bz[v-1]]]) return find(v-1,son[x][bz[v-1]],son[y][bz[v-1]])+(1<<(v-1));
return find(v-1,son[x][1-bz[v-1]],son[y][1-bz[v-1]]);
}
int main()
{
n=read(); q=read();
for (int i=1;i<=n;i++)
{
int x=read();
for (int j=0;j<Log;x/=2) bz[j++]=x % 2;
insert(Log,root[i],root[i-1]);
}
while (q--)
{
int x=read(),l=read(),r=read();
for (int j=0;j<Log;x/=2) bz[j++]=1-(x % 2);
printf("%d\n",find(Log,root[r+1],root[l]));
}
return 0;
}