256. 最大异或和
题目链接
256. 最大异或和
给定一个非负整数序列 \(a\) ,初始长度为 \(N\) 。
有 \(M\) 个操作,有以下两种操作类型:
A x
:添加操作,表示在序列末尾添加一个数 \(x\) ,序列的长度 \(N\) 增大 1 。Q l r x
:询问操作,你需要找到一个位置 \(p\) ,满足 \(l \leq p \leq r\) ,使得: \(a[p]\) xor a \([p+1]\) xor \(\ldots\) xor \(a[N]\) xor \(x\) 最 大,输出这个最大值。
输入格式
第一行包含两个整数 \(N, M\) ,含义如问题描述所示。
第二行包含 \(N\) 个非负整数,表示初始的序列 \(A_{\text {。 }}\)
接下来 \(M\) 行,每行描述一个操作,格式如题面所述。
输出格式
每个询问操作输出一个整数,表示询问的答案。
每个答案占一行。
数据范围
\( N, M \leq 3 \times 10^{5}, 0 \leq a[i] \leq 10^{7} \text { 。 } \)
输入样例:
5 5
2 6 4 3 6
A 1
Q 3 5 4
A 4
Q 5 7 0
Q 3 6 6
输出样例:
4
5
6
解题思路
可持久化 trie
可持久化 trie 关键在于维护所有版本的信息,每次插入一个数,每次创建一个根节点,并且将前面的信息复制过来,但不是完全复制,而是利用了本身的信息,如下:
即插入一个数时,要利用上一个版本的信息,一层一层的进行操作,如果上一个版本有信息,则将该层信息复制过来,再生成本层应该生成的信息,这样所有的信息都能维护到
本题即求 \(s_{p-1} \bigoplus s_n\) 的最大值,其中 \(s_i\) 为前缀异或值,\(l\leq p \leq r\),如果在 \(1\sim r\) 范围内,则可利用可持久化 trie 解决(\(root[r]\) 维护了前 \(r\) 个版本的信息),可以在每个节点上维护以该节点为子树的最大下标,当需要该节点时只需要判断该下标是否不小于 \(l\) 即可
- 时间复杂度:\(O((m+n)\times logn)\)
代码
// Problem: 最大异或和
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/258/
// Memory Limit: 512 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
const int N=6e5+5,M=N*24;
int n,m,s[N],tr[M][2],root[N],max_id[M],idx;
void insert(int i,int k,int p,int q)
{
if(k<0)
{
max_id[q]=i;
return ;
}
int v=s[i]>>k&1;
if(p)tr[q][v^1]=tr[p][v^1];
tr[q][v]=++idx;
insert(i,k-1,tr[p][v],tr[q][v]);
max_id[q]=max(max_id[tr[q][0]],max_id[tr[q][1]]);
}
int ask(int l,int root,int C)
{
int p=root;
for(int i=23;i>=0;i--)
{
int t=C>>i&1;
if(max_id[tr[p][t^1]]>=l)p=tr[p][t^1];
else
p=tr[p][t];
}
return C^s[max_id[p]];
}
int main()
{
scanf("%d%d",&n,&m);
root[0]=++idx,max_id[0]=-1;
insert(0,23,0,root[0]);
for(int i=1;i<=n;i++)
{
int x;
scanf("%d",&x);
s[i]=s[i-1]^x;
root[i]=++idx;
insert(i,23,root[i-1],root[i]);
}
char op[2];
int l,r,x;
while(m--)
{
scanf("%s",op);
if(*op=='A')
{
scanf("%d",&x);
n++;
s[n]=s[n-1]^x;
root[n]=++idx;
insert(n,23,root[n-1],root[n]);
}
else
{
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",ask(l-1,root[r-1],s[n]^x));
}
}
return 0;
}