[BZOJ]2741 [FOTILE模拟赛]L

来源:互联网 发布:杭州大数据培训机构 编辑:程序博客网 时间:2024/05/03 02:54

2741: 【FOTILE模拟赛】L

Time Limit: 15 Sec  Memory Limit: 162 MB
Submit: 2939  Solved: 850
[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]


HOME Back


这道题是裸的区间最大连续异或和,因为题目就让你求这个对吧...

考虑求前缀异或和,那么sum[L-1]^SUM[R]就是L到R得连续异或和,因为我们sum存储的是前缀,又因为相同的数异或为0,且sum[R]包含了sum[L-1],所以两者异或起来,1~L-1的异或贡献被抵消,就只剩下了L~R的贡献.那么问题就转化成为,在L-1到R内选择两个数的sum值异或起来最大.

考虑对于一个数 x 的sum,求与他之前的某个数异或起来最大,那么贪心的肯定让高位的1得到保证,由异或的性质可得我们要从高位到低位找到一个数的高位到低位的每一位尽量与x的每一位相反.那么我们对于序列上的每个点i就建立可持久化trie树维护1~i的sum值,trie树里面保存了每个数的二进制值,从高位到低位深度变深,这是一个01trie树.那么R的trie树-(L-1)trie的trie树就得到维护了L~R sum值 的01trie,那么对于这个区间里的每个数的sum就可以顺着这个01trie从高位到低位贪心选择与当前数的sum值的这一位不相同的,就可以找到最大值.但是这样对于每个询问是o(区间长度*trie树树高)的,那么我们就分块预处理处理每个块到每个点的答案(数据不大,所以可以空间允许精确到每个点),然后对于L到R包含的块的答案就能o(1)得到,不在块内的暴力查trie即可,可以结合代码理解.

#include<stdio.h>#include<cmath>#include<cstring>#include<algorithm>using namespace std;const int maxn=12005;const int maxbit=31;inline const int read(){    register int f=1,x=0;    register char ch=getchar();     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}    return f*x;}int a[maxn],c[maxn*1000][2],sum[maxn*1000],init[200][maxn],tr[maxn],st,n,m,block,blo[maxn],id,Whereever_I_Go,ed,_wanna,maxx,lastans;struct Trie{    void insert(int &rt,int pre,int who,int pos){       rt=++id;       c[rt][0]=c[pre][0];c[rt][1]=c[pre][1];       sum[rt]=sum[pre]+1;       if(pos==-1) return;       Whereever_I_Go=(who>>pos)&1;       insert(c[rt][Whereever_I_Go],c[pre][Whereever_I_Go],who,pos-1);    }    inline int query(int l,int r,int who){       ed=0;       for(int i=maxbit;i>=0;i--){           _wanna=((who>>i)&1)^1;           int p=c[l][_wanna],q=c[r][_wanna];           if(sum[q]>sum[p]) ed|=(1<<i),l=p,r=q;           else l=c[l][_wanna^1],r=c[r][_wanna^1];       }       return ed;    }}trie;int main(){    n=read(),m=read(),block=(int)sqrt(n);tr[0]=0;    for(register int i=1;i<=n;i++) a[i]=read(),a[i]^=a[i-1];    for(register int i=1;i<=n;i++) trie.insert(tr[i],tr[i-1],a[i],maxbit);    for(register int i=1;i<=n;i++) blo[i]=(i-1)/block+1;    maxx=n/block+(n%block);    for(int i=1;i<=maxx;i++){        st=(i-1)*block+1;        for(int j=st;j<=n;j++){            init[i][j]=max(init[i][j-1],a[j]^a[st-1]);            init[i][j]=max(init[i][j],trie.query(tr[st-1],tr[j],a[j]));        }    }    int l,r;    while(m--){        l=read(),r=read();        l=(l+(long long)lastans)%n+1;        r=(r+(long long)lastans)%n+1;        if(l>r) swap(l,r);l--;        lastans=(blo[r]>blo[l])?init[blo[l]+1][r]:0;        int lim=min(blo[l]*block,r);        for(int i=l;i<=lim;i++) lastans=max(lastans,trie.query(tr[l-1],tr[r],a[i]));        printf("%d\n",lastans);    }}


阅读全文
0 0
原创粉丝点击