您的位置:首页 > 其它

[BZOJ2741][FOTILE模拟赛]L-可持久化字典树-分块

2017-12-27 00:46 567 查看

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

Sample Output

5

7

7

HINT

N=12000,M=6000,x,y,Ai在signed longint范围内。

Source

By seter

虽然每个题解都有写,但是

这题的x+lastans、y+lastans可能会在signed longint范围之外

因为咱一开始没有看见直到心血来潮点开讨论

思路:

因为区间很麻烦,所以考虑记录前缀异或和,问题变成在一段区间内,两两数之间的最大异或值。

对于这种最大异或值就要想到trie。

然后因为区间询问,所以trie需要可持久化。

那么得到一个O(nm)的暴力~

考虑优化:分块。

对于每个块,预处理块的起点到块起点后面的每个位置的询问答案。

对于每个询问,首先用最近的块左端点更新答案,然后剩下部分暴力 <
11c72
br>
复杂度O(n√m),可过~

这道题可以给人一个教训:当你实在改不出来时,记得看讨论……

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

inline int read()
{
int x=0;char ch=getchar();
while(ch<'0' || '9'<ch)ch=getchar();
while('0'<=ch && ch<='9')x=x*10+(ch^48),ch=getchar();
return x;
}

typedef long long ll;

const int N=12009;
const int M=N*45;
const int K=31;

int n,m,ans;
int a
,s
,sum[119]
;
int blk,bel
,fst
;
int rt
,ch[M][2],val[M],tot;

inline void cp(int x,int y)
{
val[y]=val[x];
ch[y][0]=ch[x][0];
ch[y][1]=ch[x][1];
}

inline int insert(int pre,int dep,int x)
{
int now=++tot;
cp(pre,now);
val[now]++;

if(!dep)return now;
int nxt=(x>>(dep-1))&1;
ch[now][nxt]=insert(ch[pre][nxt],dep-1,x);
return now;
}

inline int query(int tl,int tr,int x)
{
int ret=0;
for(int i=K-1;i>=0;i--)
{
int nxt=(x>>i&1)^1;
if(val[ch[nxt]]-val[ch[tl][nxt]]>0)
ret|=1<<i,tl=ch[tl][nxt],tr=ch[nxt];
else
tl=ch[tl][nxt^1],tr=ch[nxt^1];
}
return ret;
}

int main()
{
n=read(),m=read();
rt[0]=insert(0,K,s[0]);
for(int i=1;i<=n;i++)
rt[i]=insert(rt[i-1],K,s[i]=s[i-1]^(a[i]=read()));

blk=sqrt(n);
fst[bel[1]=0]=1;
for(int i=2;i<=n;i++)
{
bel[i]=i/blk;
if(bel[i]!=bel[i-1])
fst[bel[i]]=i;
}

for(int i=0;fst[i];i++)
for(int j=fst[i]+1;j<=n;j++)
sum[i][j]=max(sum[i][j-1],query(rt[fst[i]-1],rt[j-1],s[j]));

while(m--)
{
int l=((ll)read()+(ll)ans)%(ll)n+1;
int r=((ll)read()+(ll)ans)%(ll)n+1;
if(l>r)swap(l,r);

int p=l/blk+1;
ans=sum[p][r];
for(int i=min(p*blk-1,r-1);i>=l-1;i--)
ans=max(ans,query(rt[i],rt[r],s[i]));
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: