这题是cf 1100F原题,场上一堆人做出来了,然后我线段树线性基时间也过不去,空间也过不去
看了题解后发现是个很容易的套路
我们对1...i的数组维护一个b[i]的前缀和线性基,但是线性基中的数字,我们每一位都要记录一个pos[k]表示p[k]是由第pos[k]个数字填进去的,在插入的时候,我们让k从高往低优先插入当前位置大的数字,就算当前p[i]已经有数字了,如果pos[k]<当前插入数字的id,那么我们把p[i]和插入的x交换,因为要让更靠右的数字尽可能插入在更高位。
这样我们求l,r中线性基最大值,就从去b[r]中,从高到底,如果当前pos[k]>=l,那么说明p[i]是由l-r中的数字异或出来的,那么我们就可以考虑是否对答案res进行异或p[k]。
#include<bits/stdc++.h>
#define maxl 1000010
using namespace std;
int n,m,ans;
int a[maxl];
struct LB
{
int p[31],pos[31];
inline void init()
{
for(int i=0;i<=30;i++)
p[i]=0,pos[i]=0;
}
inline void insert(int x,int id)
{
for(int i=30;i>=0;i--)
if(x&(1<<i))
{
if(!p[i])
{
p[i]=x;
pos[i]=id;
return;
}
if(id>pos[i])
{
swap(x,p[i]);
swap(id,pos[i]);
}
x^=p[i];
}
}
inline int getmax(int l)
{
int res=0;
for(int i=30;i>=0;i--)
if(pos[i]>=l && (res^p[i])>res)
res^=p[i];
return res;
}
}b[maxl];
inline void prework()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
b[i]=b[i-1];
b[i].insert(a[i],i);
}
}
inline void mainwork()
{
int l,r,op,x;ans=0;
for(int i=1;i<=m;i++)
{
scanf("%d",&op);
if(op==0)
{
scanf("%d%d",&l,&r);
l=(l^ans)%n+1;
r=(r^ans)%n+1;
if(l>r) swap(l,r);
ans=b[r].getmax(l);
printf("%d\n",ans);
}
else
{
scanf("%d",&x);
x^=ans;
a[++n]=x;
b[n]=b[n-1];
b[n].insert(a[n],n);
}
}
}
inline void print()
{
}
int main()
{
int t;
scanf("%d",&t);
for(int i=1;i<=t;i++)
{
prework();
mainwork();
print();
}
return 0;
}