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 ).
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
HINT
N=12000,M=6000,x,y,Ai在signed longint范围内。
函数性编程神题。
看dyf神牛题解学会的。
首先提一下,这道题是没有负数的。
然后我们用s[i]表示前i个数的xor和。
那么询问[l,r]里的最大一段的xor和就变成了询问最大的s[i] xor s[j] (i,j∈[l-1,r])。
对于给定的i,我们可以将[l-1,r]的数建一个trie树,然后每次尝试走跟i当前位相反的节点,就可以得到对于i的最大xor和。
这里用到了函数性编程,这个trie树明显是可减的。简单来说就是假设插入了第i个数后trie树入口为ent[i],那么想要访问[l,r]的trie树,就从ent[r]节点进入,所有编号小于ent[l]的节点全部无视即可。
这样我们可以在log级时间内求出对于一个[l,r],某个i的最大xor和。
虽然如此,但是爆搞明显是不可以的。
解决这种问题,很容易想到分块。
我们将sqrt(n)个分为一块,然后可以在log * n^1.5的时间内求出所有块之间的最大xor和,将其保存起来,利用二维st算法用(sqrt(n)log)^2=n log^2的时间内预处理,就可以在O(1)的时间内回答端点在某些连续段的最大xor值。
之后考虑端点在两端不完整块上的情况,暴力枚举即可,明显枚举不超过2*sqrt(n)个点,每次查询花费log时间。
算法总体复杂度为O(n^1.5*log+m*sqrt(n)*log),可以再规定时限内通过所有测试点。
虽然这么说,但是我写的比较悬……14848ms才跑完。
program bzoj2741;
const
len=110;
var
l,r,ans,all,tot,n,m,i,j,k,q,p:longint;
two:array [0..32] of longint;
ent,s,form:array [0..12001] of longint;
u:array [0..111,0..111] of longint;
fin:array [0..121] of longint;
trie:array [0..500001,0..1] of longint;
max:array [0..11,0..111,0..11,0..111] of longint;
procedure swap (var a,b:longint);inline;
begin
if a=b then exit;
b:=a xor b;
a:=a xor b;
b:=a xor b;
end;
procedure add (x,last,now:longint);
var
i,k:longint;
begin
for i:=30 downto 0 do
begin
k:=x and two[i];
if k<>0 then k:=1;
if last<>-1 then
begin
trie[now]:=trie[last];
inc(tot);
trie[now,k]:=tot;
now:=tot;
if trie[last,k]=0 then
last:=-1
else
last:=trie[last,k];
end
else
begin
inc(tot);
trie[now,k]:=tot;
now:=tot
end;
end;
end;
function find (x,l,now:longint):longint;
var
ans,i,k:longint;
begin
if l=0 then inc(l);
ans:=0;
for i:=30 downto 0 do
begin
k:=x and two[i];
if k<>0 then k:=1;
if (trie[now,k xor 1]>=l) then
begin
ans:=ans+two[i];
now:=trie[now,k xor 1];
end
else
now:=trie[now,k];
end;
exit(ans);
end;
function qmax (l,r:longint):longint;
var
i,k:longint;
begin
if l>r then swap(l,r);
i:=trunc(ln(r-l+1)/ln(2));
k:=0;
if max[i,l,i,l]>k then
k:=max[i,l,i,l];
if max[i,l,i,r-(1 shl i) + 1]>k then
k:=max[i,l,i,r-(1 shl i) + 1];
if max[i,r-(1 shl i) + 1,i,l]>k then
k:=max[i,r-(1 shl i) + 1,i,l];
if max[i,r-(1 shl i) + 1,i,r-(1 shl i) + 1]>k then
k:=max[i,r-(1 shl i) + 1,i,r-(1 shl i) + 1];
exit(k);
end;
begin
read(n,m);
for i:=0 to 30 do
two[i]:=1 shl i;
for i:=1 to n do
begin
read(s[i]);
s[i]:=s[i] xor s[i-1];
inc(tot);
ent[i]:=tot;
add(s[i],ent[i-1],ent[i]);
end;
for i:=0 to n do
begin
form[i]:=i div len + 1;
fin[form[i]]:=i;
end;
all:=n div len + 1;
for i:=0 to n do
for j:=1 to all do
begin
k:=find(s[i],ent[j*len-len],ent[fin[j]]);
if k>u[form[i],j] then
u[form[i],j]:=k;
end;
for i:=1 to all do
for j:=1 to all do
max[0,i,0,j]:=u[i,j];
i:=0;
while 1 shl i <= all do
begin
for q:=1 to all do
for p:=1 to all do
if q + (1 shl i)>all then
max[i+1,q,0,p]:=max[i,q,0,p]
else
if max[i,q,0,p]>max[i,q+(1 shl i),0,p] then
max[i+1,q,0,p]:=max[i,q,0,p]
else
max[i+1,q,0,p]:=max[i,q+(1 shl i),0,p];
j:=0;
while 1 shl j<= all do
begin
for q:=1 to all do
for p:=1 to all do
if p+(1 shl j)>all then
max[i+1,q,j+1,p]:=max[i+1,q,j,p]
else
if max[i+1,q,j,p]>max[i+1,q,j,p+(1 shl j)] then
max[i+1,q,j+1,p]:=max[i+1,q,j,p]
else
max[i+1,q,j+1,p]:=max[i+1,q,j,p+(1 shl j)];
inc(j);
end;
inc(i);
end;
ans:=0;
for j:=1 to m do
begin
read(l,r);
l:=(int64(l)+ans) mod n + 1;
r:=(int64(r)+ans) mod n + 1;
if l>r then swap(l,r);
dec(l);
ans:=0;
if form[l]=form[r] then
begin
for i:=l to r do
begin
k:=find(s[i],ent[l],ent[r]);
if k>ans then ans:=k;
end;
writeln(ans);
continue;
end;
if form[l]+1<=form[r]-1 then
ans:=qmax(form[l]+1,form[r]-1);
for i:=l to fin[form[l]] do
begin
k:=find(s[i],ent[l],ent[r]);
if k>ans then ans:=k;
end;
for i:=form[r]*len-len to r do
begin
k:=find(s[i],ent[l],ent[r]);
if k>ans then ans:=k;
end;
writeln(ans);
end;
end.