BZOJ2741:[FOTILE模拟赛]L
Description
FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和。
即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r。
为了体现在线操作,对于一个询问(x,y):
l=min(((x+lastans)mod N)+1,((y+lastans)mod N)+1).
r=max(((x+lastans)mod N)+1,((y+lastans)mod N)+1).
其中lastans是上次询问的答案,一开始为0。
Input
第一行两个整数N和M。
第二行有N个正整数,其中第i个数为Ai,有多余空格。
后M行每行两个数x,y表示一对询问。
Output
共M行,第i行一个正整数表示第i个询问的结果。
Sample Input
3 3
1 4 3
0 1
0 1
4 3
1 4 3
0 1
0 1
4 3
Sample Output
5
7
7
7
7
HINT
N=12000,M=6000,x,y,Ai在signed longint范围内。
题解:
把元素数组aa替换为前缀异或和数组qz,则询问变成了指定区间内最大的两个元素异或和。
假如某个元素x已经确定,那么我们只要在区间中找到一个数y,使x xor y最大。
这可以用字典树在O(log)的复杂度内实现。因为是指定的一个区间,所以要采用可持久化字典树。
为了减少复杂度,采取分块的做法。
将n分为√n块,对于每块的第一个元素i,用a[i,j]表示i到j的区间中的最大连续异或和。
转移方式:a[i,j]:=max(a[i,j-1],qz[j]在[i,j-1]的字典树中的最大异或和)。
注意不要忘了以[i,j]异或和作为答案的情况(即qz[i-1]xor qz[j])。
预处理好a数组后,开始处理询问[l,r]。
找到第一个比l大的分块首元素i(i=k*√n+1),分情况讨论。
若r≥i,则答案为max(a[i,r],qz[l≤j≤i-1]在[j+1,r]的字典树中的最大异或和);
若r<i,则答案为max(qz[l≤j≤r]在[l,j-1]的字典树中的最大异或和),注意考虑以[l,j]异或和作为答案的情况(即qz[l-1]xor qz[j])。
代码:
1 uses math; 2 var 3 t:array[0..600000,0..1,0..1]of longint; 4 a:array[0..120,0..12001]of longint; 5 qz,aa:array[0..12001]of longint; 6 r:array[0..12001]of longint; 7 b:array[0..34]of longint; 8 i,ii,j,k,n,m,block,mm,cnt,x,y,ans:longint; 9 l,ll,rr:int64; 10 procedure cl(y,yy,z:longint); 11 var i:longint; 12 begin 13 if z=-1 then exit; 14 i:=x and(1 shl z); 15 if i>0 then 16 begin 17 inc(cnt); t[yy,0]:=t[y,0]; 18 t[yy,1,1]:=cnt; t[yy,1,0]:=t[y,1,0]+1; 19 cl(t[y,1,1],t[yy,1,1],z-1); exit; 20 end; 21 inc(cnt); t[yy,1]:=t[y,1]; 22 t[yy,i,1]:=cnt; t[yy,i,0]:=t[y,i,0]+1; 23 cl(t[y,i,1],t[yy,i,1],z-1); 24 end; 25 function qq(y,yy,z:longint):longint; 26 var i:longint; 27 begin 28 if z=-1 then exit(0); 29 i:=x and(1 shl z); 30 if i>0 then 31 begin 32 if t[yy,0,0]-t[y,0,0]>0 then 33 exit(b[z]+qq(t[y,0,1],t[yy,0,1],z-1)); 34 exit(qq(t[y,1,1],t[yy,1,1],z-1)); 35 end; 36 if t[yy,1,0]-t[y,1,0]>0 then 37 exit(b[z]+qq(t[y,1,1],t[yy,1,1],z-1)); 38 exit(qq(t[y,0,1],t[yy,0,1],z-1)); 39 end; 40 begin 41 b[0]:=1; 42 for i:=1 to 30 do b[i]:=b[i-1]*2; 43 readln(n,m); 44 for i:=1 to n do 45 begin 46 read(aa[i]); qz[i]:=aa[i] xor qz[i-1]; x:=qz[i]; 47 inc(cnt); r[i]:=cnt; cl(r[i-1],cnt,30); 48 end; 49 block:=trunc(sqrt(n)*1.5)+1; 50 block:=min(n,block); 51 i:=1; 52 while i<=n do 53 begin 54 inc(mm); 55 a[mm,i]:=aa[i]; 56 for j:=i+1 to n do 57 begin 58 x:=qz[j]; a[mm,j]:=max(a[mm,j-1],x xor qz[i-1]); 59 a[mm,j]:=max(a[mm,j],qq(r[i-1],r[j-1],30)); 60 end; 61 i:=i+block; 62 end; 63 for i:=1 to m do 64 begin 65 readln(ll,rr); 66 l:=max((ll+ans)mod n+1,(rr+ans)mod n+1); 67 ll:=min((ll+ans)mod n+1,(rr+ans)mod n+1); 68 k:=l; j:=ll; l:=0; 69 while block*l+1<=j do inc(l); 70 if block*l+1<=k then 71 begin 72 ans:=a[l+1,k]; l:=block*l; 73 for ii:=j to l do 74 begin 75 x:=qz[ii-1]; 76 ans:=max(ans,qq(r[ii-1],r[k],30)); 77 end; 78 end else 79 begin 80 ans:=aa[j]; 81 for ii:=j+1 to k do 82 begin 83 x:=qz[ii]; ans:=max(ans,x xor qz[j-1]); 84 ans:=max(ans,qq(r[j-1],r[ii-1],30)); 85 end; 86 end; 87 writeln(ans); 88 end; 89 end.