神题……Orz zyf & lyd
首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问【某个区间中最大的区间异或和】改变成【某个区间中 max(两个数的异或和)】
要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了;然而我们并不能。
一个常见的折中方案:分块!
这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值。
我们不预处理所有的左端点,我们只预处理$\sqrt{n}$个左端点,与$n$个右端点的答案。
也就是说:将序列分成$\sqrt{n}$块,b[i][j]表示在块 i 的左端到位置 j 这个区间中,选出两个数,其最大的Xor值。
对于询问[l,r]:设p是$l$后面第一个块的左端点,[p,r]的答案已经在b[p][r]中,[l,p]的答案就是对[l,p]中每个数x执行ask(l,r,x);
最后:ask(l,r,x)用可持久化Trie实现:具体来说就是,如果能往1走就往1走,如果1这棵子树中所有点都是出现在$l$之前的,那么就往0走。
可持久化Trie的写法……根据可持久化线段树的写法,yy一下试试?其实差不多= =
1 /************************************************************** 2 Problem: 2741 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:6636 ms 7 Memory:148948 kb 8 ****************************************************************/ 9 10 //BZOJ 2741 11 #include<cstdio> 12 #include<cmath> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 typedef long long LL; 23 inline int getint(){ 24 int r=1,v=0; char ch=getchar(); 25 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 26 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 27 return r*v; 28 } 29 const int N=150010,M=5e6+10; 30 /*******************template********************/ 31 32 int n,m,q,tot,rt[N],id[M],t[M][2],a[N],b[150][N]; 33 34 inline void Ins(int pre,int x,int k){ 35 int now=rt[k]=++tot; id[tot]=k; 36 D(i,30,0){ 37 int j=(x>>i)&1; 38 t[now][j^1]=t[pre][j^1]; 39 t[now][j]=++tot; id[tot]=k; 40 now=tot; 41 pre=t[pre][j]; 42 } 43 } 44 inline int ask(int l,int r,int x){ 45 int ans=0,now=rt[r]; 46 D(i,30,0){ 47 int j=((x>>i)&1)^1; 48 if (id[t[now][j]]>=l) ans|=1<<i; else j^=1; 49 now=t[now][j]; 50 } 51 return ans; 52 } 53 54 int main(){ 55 #ifndef ONLINE_JUDGE 56 freopen("2741.in","r",stdin); 57 freopen("2741.out","w",stdout); 58 #endif 59 n=getint(); q=getint(); 60 F(i,1,n) a[i]=a[i-1]^getint(); 61 id[0]=-1; 62 Ins(rt[0],a[0],0); 63 F(i,1,n) Ins(rt[i-1],a[i],i); 64 int len=sqrt(n); m=n/len+(n%len!=0); 65 rep(i,m) F(j,i*len+1,n) 66 b[i][j]=max(b[i][j-1],ask(i*len,j-1,a[j])); 67 int ans=0; 68 F(i,1,q){ 69 int x=((LL)ans+(LL)getint())%n+1,y=((LL)ans+(LL)getint())%n+1; 70 if (x>y) swap(x,y); 71 x--; 72 int bx=x/len+(x%len!=0); 73 ans=bx*len < y ? b[bx][y] : 0; 74 F(j,x,min(bx*len,y)) 75 ans=max(ans,ask(x,y,a[j])); 76 printf("%d\n",ans); 77 } 78 return 0; 79 }