背景:
h
e
h
e
.
.
.
hehe...
hehe...
题目传送门:
https://www.luogu.org/problemnew/show/P4735
题意:
一个序列,支持两种操作加入一个元素
x
x
x或给出
l
,
r
,
x
l,r,x
l,r,x,询问在
[
l
,
r
]
[l,r]
[l,r]中找到一个点
p
p
p,使得
a
p
⊕
a
p
+
1
⊕
a
p
+
2
⊕
.
.
.
⊕
a
n
⊕
x
a_p⊕a_{p+1}⊕a_{p+2}⊕...⊕a_{n}⊕x
ap⊕ap+1⊕ap+2⊕...⊕an⊕x最大,求这个的最大值。
思路:
back to summary
\text{back to summary}
back to summary.
异或的解决方法一般有线性基和
01Trie
\text{01Trie}
01Trie。
这是一道动态的问题,需要动态的方式,当然是动态
01Trie
\text{01Trie}
01Trie,即可持久化
01Trie
\text{01Trie}
01Trie。
其实我们知道可持久化线段树(一种实现方式是主席树),运用类似的思想构建一棵可持久化
01Trie
\text{01Trie}
01Trie。
我们可以求出异或前缀
p
r
e
i
pre_i
prei。
a
p
⊕
a
p
+
1
⊕
a
p
+
2
⊕
.
.
.
⊕
a
n
⊕
x
a_p⊕a_{p+1}⊕a_{p+2}⊕...⊕a_{n}⊕x
ap⊕ap+1⊕ap+2⊕...⊕an⊕x
= p r e p − 1 ⊕ p r e n ⊕ x =pre_{p-1}⊕pre_{n}⊕x =prep−1⊕pren⊕x
=
p
r
e
p
−
1
⊕
(
p
r
e
n
⊕
x
)
=pre_{p-1}⊕(pre_{n}⊕x)
=prep−1⊕(pren⊕x)
而
p
r
e
n
⊕
x
pre_{n}⊕x
pren⊕x是已知的,不妨设为
S
S
S。
我们就转化成求
S
⊕
p
r
e
p
−
1
S⊕pre_{p-1}
S⊕prep−1的最大值,其中
p
∈
[
l
,
r
]
p∈[l,r]
p∈[l,r]。
这等价于求
S
⊕
p
r
e
p
S⊕pre_{p}
S⊕prep的最大值,其中
p
∈
[
l
−
1
,
r
−
1
]
p∈[l-1,r-1]
p∈[l−1,r−1]。
注意一下
l
=
1
l=1
l=1(即
l
−
1
=
0
l-1=0
l−1=0)时要特判一下。
还是递归版比较和谐。
over.
\text{over.}
over.
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int root[20000000],tot[20000000],pre[600010];
int tr[20000000][2];
int n,m,len=0;
void insert(int now,int last,int t,int x)
{
if(t<0) return;
int tmp=(x>>t)&1;
tr[now][tmp]=++len;
tr[now][tmp^1]=tr[last][tmp^1];
tot[tr[now][tmp]]=tot[tr[last][tmp]]+1;
insert(tr[now][tmp],tr[last][tmp],t-1,x);
}
int query(int now,int last,int t,int x)
{
if(t<0) return 0;
int tmp=(x>>t)&1;
if(tot[tr[now][tmp^1]]<tot[tr[last][tmp^1]]) return (1<<t)|query(tr[now][tmp^1],tr[last][tmp^1],t-1,x); else return query(tr[now][tmp],tr[last][tmp],t-1,x);
}
int main()
{
int l,r,x;
char s[5];
scanf("%d %d",&n,&m);
root[0]=++len;
insert(root[0],0,25,0);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
pre[i]=pre[i-1]^x;
root[i]=++len;
insert(root[i],root[i-1],25,pre[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
if(s[1]=='A')
{
scanf("%d",&x);
n++;
pre[n]=pre[n-1]^x;
root[n]=++len;
insert(root[n],root[n-1],25,pre[n]);
}
else
{
scanf("%d %d %d",&l,&r,&x);
l--,r--;
printf("%d\n",query(!l?0:root[l-1],root[r],25,x^pre[n]));
}
}
}