https://www.lydsy.com/JudgeOnline/problem.php?id=3261
看了看可持久化trie,发现跟主席树的思想一毛一样,遵循罗哥的思想看懂算法不看代码自己实现一发就过了真爽
此题所求可以转化为在sum[l-1]----sum[r-1]中找一个数字与sum[n]^x 异或最大,很显然就是trie的经典应用。
我们对于异或前缀和建立前i个异或前缀和的trie,我们从前r-1个异或前缀和的根节点rt[r-1]向下跑异或最大,注意由于要>=l-1,于是在insert注意标记一下每个节点是由哪个位置生成的,在跑异或最大的时候判断一下是否符合条件
#include<bits/stdc++.h>
using namespace std;
const int maxl=6e5+10;
int n,m,tot,ans;
int a[maxl],sum[maxl],rt[maxl],mi[30];
int tr[maxl*30][2],lst[maxl*30];
char s[2];
inline void insert(int &x,int k,int i)
{
++tot;
tr[tot][0]=tr[x][0];tr[tot][1]=tr[x][1];
x=tot;lst[tot]=i;
if(k<0) return;
if(sum[i]&(1<<k))
insert(tr[tot][1],k-1,i);
else
insert(tr[tot][0],k-1,i);
}
inline void prework()
{
mi[0]=1;
for(int i=1;i<=25;i++)
mi[i]=mi[i-1]*2;
scanf("%d%d",&n,&m);
n+=1;a[1]=0;sum[1]=0;
for(int i=2;i<=n;i++)
{
scanf("%d",&a[i]);
sum[i]=sum[i-1]^a[i];
}
for(int i=1;i<=n;i++)
{
rt[i]=rt[i-1];
insert(rt[i],25,i);
}
}
inline int ask(int l,int r,int t)
{
int u=rt[r-1];ans=0;
for(int k=25;k>=0;k--)
if(t&mi[k])
{
if(lst[tr[u][0]]>=l-1)
{
ans|=mi[k];
u=tr[u][0];
}
else
u=tr[u][1];
}
else
{
if(lst[tr[u][1]]>=l-1)
{
ans|=mi[k];
u=tr[u][1];
}
else
u=tr[u][0];
}
return ans;
}
inline void mainwork()
{
int l,r,x,t,u;
for(int i=1;i<=m;i++)
{
scanf("%s",s);
if(s[0]=='A')
{
scanf("%d",&x);
a[++n]=x;
sum[n]=sum[n-1]^a[n];
rt[n]=rt[n-1];
insert(rt[n],25,n);
}
else
{
scanf("%d%d%d",&l,&r,&x);
l++;r++;
t=x^sum[n];
printf("%d\n",ask(l,r,t));
}
}
}
int main()
{
prework();
mainwork();
return 0;
}