Description
给定一个非负整数序列
a
{a}
a,初始长度为
N
N
N。
有
M
M
M个操作,有以下两种操作类型:
1、
A
x
A x
Ax :添加操作,表示在序列末尾添加一个数x,序列的长度N+1。
2、
Q
l
r
x
Q l r x
Qlrx :询问操作,你需要找到一个位置
p
p
p,满足
l
<
=
p
<
=
r
l<=p<=r
l<=p<=r,使得:
a
[
p
]
a[p]
a[p]
x
o
r
xor
xor
a
[
p
+
1
]
a[p+1]
a[p+1]
x
o
r
xor
xor
.
.
.
...
...
x
o
r
xor
xor
a
[
N
]
a[N]
a[N]
x
o
r
xor
xor
x
x
x 最大,输出最大是多少。
Input
第一行包含两个整数
N
N
N ,
M
M
M,含义如问题描述所示。
第二行包含
N
N
N个非负整数,表示初始的序列
A
A
A 。
接下来
M
M
M行,每行描述一个操作,格式如题面所述
题解:
可持久化 T r i e Trie Trie树
这个题我们维护前缀异或值,因为要加入新的值在后面。
然后对于每个前缀异或值,都建一个 T r i e Trie Trie树,最后询问的时候在 l l l到 r r r区间中取数,因为要异或 x x x最大,所以我们贪心走当前二进制位的反向边即可。
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e7+50;
int tot,n,m,root[MAXN],a[MAXN];
int cnt[MAXN],nxt[MAXN][2];
inline void Insert(int idx,int x){
int pre = root[idx-1],now = ++tot;
root[idx] = now;
for(int i=23;i>=0;i--){
int k = (x>>i)&1;
cnt[now] = cnt[pre] + 1;
nxt[now][k^1] = nxt[pre][k^1];
nxt[now][k] = ++tot;
now = nxt[now][k];
pre = nxt[pre][k];
}
cnt[now] = cnt[pre] + 1;
}
inline int Query(int l,int r,int x){
int ll = root[l],rr = root[r],res = 0;
for(int i=23;i>=0;i--){
int k = (x>>i)&1;
if(cnt[nxt[rr][k^1]]-cnt[nxt[ll][k^1]]) res += 1<<i,k^=1;
ll = nxt[ll][k];
rr = nxt[rr][k];
}
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
Insert(1,0);
for(int i=1;i<=n;i++) a[i]^=a[i-1],Insert(i+1,a[i]);
while(m--){
char op; int l,r,x;
scanf(" %c",&op);
if(op=='A'){
scanf("%d",&x);
a[++n] = a[n-1]^x;
Insert(n+1,a[n]);
}
else {
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",Query(l-1,r,a[n]^x));
}
}
return 0;
}