[BZOJ 2741]【FOTILE模拟赛】L 分块+可持久trie树

来源:互联网 发布:大数据工程师工作强度 编辑:程序博客网 时间:2024/05/19 23:18

首先很显然维护异或前缀和让询问区间连续一段变成询问两个单点.

然后就比较套路了,发现每一次都是询问一个区间内而且不满足我们已知知识内的一些特殊性质例如单调性,但是暴力又可以很容易的做出来,所以这个时候就可以考虑分块了设f[i][j] 表示第i块开始到j的最大异或值,然后就很简单了

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#define LL long long#define maxn 20021using namespace std;int f[400][maxn],a[maxn],sum[maxn*40],ch[maxn*40][2],rt[maxn];int tot,n,m,block,bl[maxn],num;void insert(int x,int& y,int val){int root;root=y=++tot,sum[y]=sum[x]+1;for(int c,i=30;i>=0;i--){c=(val>>i)&1;ch[root][!c]=ch[x][!c];root=ch[root][c]=++tot;x=ch[x][c];sum[root]=sum[x]+1;}}int query(int a,int b,int val){a=rt[a-1],b=rt[b];int ans=0;for(int c,i=30;i>=0;i--){c=(val>>i)&1;if(sum[ch[b][!c]]-sum[ch[a][!c]])ans=ans<<1|1,b=ch[b][!c],a=ch[a][!c];else ans=ans<<1,a=ch[a][c],b=ch[b][c];}return ans;}void solve(){LL l,r,x,y;int ans=0;while(m--){scanf("%lld%lld",&x,&y);l=(x+ans)%n+1,r=(y+ans)%n+1;if(l>r)swap(l,r);l--,ans=0;if(bl[l]==bl[r]){for(int i=l;i<=r;i++)ans=max(ans,query(l,r,a[i]));printf("%d\n",ans);}else{int t=bl[l]*block;ans=f[bl[l]+1][r];for(int i=l;i<=t;i++)ans=max(ans,query(l,r,a[i]));printf("%d\n",ans);}}}int main(){scanf("%d%d",&n,&m);block=sqrt(n);num=n/block+(n%block!=0);insert(rt[0],rt[0],0);for(int i=1;i<=n;i++){scanf("%d",a+i),a[i]^=a[i-1];insert(rt[i-1],rt[i],a[i]);bl[i]=(i-1)/block+1;}for(int s,i=1;i<=num;i++){s=(i-1)*block+1;for(int j=s;j<=n;j++){f[i][j]=max(f[i][j-1],query(s,j,a[j]));}}solve();return 0;}


0 0
原创粉丝点击