题目:BZOJ3261.
题目大意:给定一个长度为
n
n
n的序列
a
a
a,支持两种操作:
1.在序列尾插入一个数字.
2.求一个在区间
[
l
,
r
]
[l,r]
[l,r]内的
p
p
p使得
a
[
p
]
 
x
o
r
 
a
[
p
+
1
]
 
x
o
r
 
.
.
.
 
x
o
r
 
a
[
n
]
 
x
o
r
 
x
a[p]\,xor\,a[p+1]\,xor\,...\,xor\,a[n]\,xor\,x
a[p]xora[p+1]xor...xora[n]xorx最大,并输出这个值.
设操作次数为
m
m
m,则
1
≤
n
,
m
≤
3
∗
1
0
5
1\leq n,m\leq 3*10^5
1≤n,m≤3∗105.
考虑将原序列
a
a
a的前缀异或数组
s
s
s写出来,那么要求最大的值为:
a
[
p
]
 
x
o
r
 
a
[
p
+
1
]
 
x
o
r
 
.
.
.
 
x
o
r
 
a
[
n
]
=
s
[
p
−
1
]
 
x
o
r
 
s
[
n
]
 
x
o
r
 
x
a[p]\,xor\,a[p+1]\,xor\,...\,xor\,a[n]=s[p-1]\,xor\,s[n]\,xor\,x
a[p]xora[p+1]xor...xora[n]=s[p−1]xors[n]xorx.
发现这个式子中 s [ n ]   x o r   x s[n]\,xor\,x s[n]xorx是确定的,我们只需要求出最优的 s [ p − 1 ] s[p-1] s[p−1]即可.
考虑没有区间限制时,这道题就可以直接用0-1 Trie维护异或的套路来做.
再考虑有区间限制时,将0-1 Trie换成可持久化0-1 Trie即可.可持久化0-1 Trie的实现与可持久化线段树类似,不再赘述.
代码如下(为了方便处理,我往第 1 1 1个节点前加了一个数即第 2 2 2棵树对应第 1 1 1个串):
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=300000,C=25;
char rc(){
char c=getchar();
while (c<'A'||c>'Z') c=getchar();
return c;
}
struct Trie{
int s[2],cnt;
}tr[N*(C+2)*2+9];
int rot[N*2+9],cr,cn;
void Build(){cr=cn=0;}
/*void Insert(int a){
tr[++cn]=tr[cr];rot[++cr]=cn;
int x=rot[cr],x0=rot[cr-1];
for (int i=C;i>=0;--i){
++tr[x].cnt;
tr[++cn]=tr[tr[x0].s[a>>i&1]];
tr[x].s[a>>i&1]=cn;
x=cn;
x0=tr[x0].s[a>>i&1];
}
++tr[x].cnt;
}*/
void Insert(int a){
rot[++cr]=++cn;
int x=rot[cr],x0=rot[cr-1];
for (int i=C;i>=0;--i){
tr[x]=tr[x0];++tr[x].cnt;
tr[x].s[a>>i&1]=++cn;x=cn;
x0=tr[x0].s[a>>i&1];
}
tr[x]=tr[x0];++tr[x].cnt;
}
//被注释掉的Insert是错误写法,应该要等到指针指到了x节点才可以给x节点赋初值,不然x指针会跳到前面的版本上
int Query(int l,int r,int a){
int xl=rot[l-1],xr=rot[r],ans=0,t;
for (int i=C;i>=0;--i){
t=a>>i&1;
if (tr[tr[xr].s[t^1]].cnt-tr[tr[xl].s[t^1]].cnt>0)
ans|=1<<i,xl=tr[xl].s[t^1],xr=tr[xr].s[t^1];
else xl=tr[xl].s[t],xr=tr[xr].s[t];
}
return ans;
}
int n,m,s[N*2+9];
Abigail into(){
Build();
Insert(0);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i){
scanf("%d",&s[i]);
s[i]^=s[i-1];
Insert(s[i]);
}
}
Abigail getans(){
char opt;
int l,r,x;
for (int i=1;i<=m;++i){
opt=rc();
if (opt=='A'){
scanf("%d",&x);
s[n+1]=s[n]^x;
Insert(s[++n]);
}else{
scanf("%d%d%d",&l,&r,&x);
printf("%d\n",Query(l,r,s[n]^x));
}
}
}
int main(){
into();
getans();
return 0;
}
本文详细解析了BZOJ3261题目的算法思路,通过使用可持久化0-1 Trie解决序列操作问题,实现高效查询区间内异或最大值。代码示例清晰展示了算法实现过程。
822

被折叠的 条评论
为什么被折叠?



