您的位置:首页 > 其它

bzoj 2741: 【FOTILE模拟赛】L (分块+可持久化trie树)

2017-01-20 16:49 423 查看

2741: 【FOTILE模拟赛】L

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 2572  Solved: 735

[Submit][Status][Discuss]

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

HINT

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

Source

By seter

[Submit][Status][Discuss]

题解:分块+可持久化trie树

对于每个点维护1到i的异或前缀和,那么我们查询一段区间的异或和就转换成了求解两个点异或的最大值。

对于序列进行分块,用f[i][j]表示区间的左右端点在块i,j之间的两点异或的最大值。

对于序列建可持久化trie树

f[i][j]=max(f[i][j-1],右端点在块j左端点在该点到i的起始位置的两点异或最大值)

对于每个点可以利用trie树O(logn)的查询。

然后询问的时候直接利用f数组,然后半块的部分进行暴力。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 120
#define M 20000
#define bi 30
#define LL long long
using namespace std;
int f

,b[M],a[M];
int sz,root[M],n,m,ch[M*60][3],size[M*60],l[M],r[M],belong[M];
void insert(int i,int x)
{
int pre=root[i-1];
root[i]=++sz;
int now=root[i];
for (int i=bi;i>=0;i--) {
LL t=(x>>i)&1;
size[now]=size[pre]+1;
ch[now][t^1]=ch[pre][t^1];
ch[now][t]=++sz;
now=ch[now][t]; pre=ch[pre][t];
}
size[now]=size[pre]+1;
}
int find(int x,int i,int j)
{
int a=root[i]; int b=root[j]; int ans=0;
for (int i=bi;i>=0;i--) {
LL t=(x>>i)&1;
if (size[ch[a][t^1]]!=size[ch[b][t^1]])
t^=1;
a=ch[a][t]; b=ch[b][t];
ans+=(1<<i)*t;
}
return ans;
}
int build(int now)
{
int ans=0;
for (int i=l[now];i<=r[now]-1;i++)
for (int j=i+1;j<=r[now];j++)
ans=max(ans,b[j]^b[i-1]),ans=max(ans,a[i]);
ans=max(ans,a[r[now]]);
if (l[now]==r[now]) return a[l[now]];
return ans;
}
int main()
{
freopen("a.in","r",stdin);
freopen("my.out","w",stdout);
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]^a[i];
memset(root,0,sizeof(root));
insert(1,0LL);
for (int i=1;i<=n;i++)
insert(i+1,b[i]);
int block=sqrt(n*1.0);
int t=ceil(n*1.0/block);
for (int i=1;i<=n;i++) belong[i]=(i-1)/block+1;
for (int i=1;i<=t;i++) l[i]=n+1,r[i]=0;
for (int i=1;i<=n;i++) {
int t=belong[i];
l[t]=min(l[t],i);
r[t]=max(r[t],i);
}
for (int i=1;i<=t;i++) f[i][i]=build(i);
for (int i=1;i<=t-1;i++)
for (int j=i+1;j<=t;j++){
f[i][j]=f[i][j-1];
for (int k=l[j];k<=r[j];k++)
f[i][j]=max(f[i][j],find(b[k],l[i]-1,k)^b[k]),f[i][j]=max(f[i][j],a[k]);
}
int ans=0;
for (int j=1;j<=m;j++) {
int x,y; scanf("%d%d",&x,&y);
x=((LL)x+ans)%n+1; y=((LL)y+ans)%n+1;
if (x>y) swap(x,y);
ans=0;
if (belong[x]==belong[y]) {
for (int i=x;i<=y;i++)
ans=max(ans,find(b[i],(int)x-1,i)^b[i]);
printf("%d\n",ans);
continue;
}
if (belong[x]+1<=belong[y]-1) ans=f[belong[x]+1][belong[y]-1];
for (int i=x;i<=r[belong[x]];i++)
ans=max(ans,find(b[i-1],i,(int)y+1)^b[i-1]);
for (int i=l[belong[y]];i<=y;i++)
ans=max(ans,find(b[i],(int)x,i+1)^b[i]);
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: