【BZOJ2741】FOTILE模拟赛 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

HINT

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

Source

By seter

可持久化Trie+分块 感觉这东西挺厉害的..我是第一次写可持久化Trie
记前缀异或和,用分块维护
因此,我们可以发现每个块的左端点与另一个任意位置的数值异或和中选一个最大值,就是对应区间的最大异或和
所以记录一下每个块左端点与另一个位置之间最大两数异或和,用f[i][j]表示,用trie进行DP.
然后对每个询问,整块的用DP值整块搞,零散的放进trie跑暴力.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define GET (ch>='0'&&ch<='9')
#define SIZE 800010
#define MAXN 12010
using namespace std;
void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
int n,m,size,cnt,num,lastans;
int a[MAXN],root[MAXN],ls[SIZE],rs[SIZE],sz[SIZE],f[120][MAXN];
void insert(int x,int &y,int val,int dep)
{
    sz[y=++num]=sz[x]+1;
    if (dep<0)  return;
    ls[y]=ls[x];rs[y]=rs[x];
    if (val&(1<<dep))   insert(rs[x],rs[y],val,dep-1);
    else    insert(ls[x],ls[y],val,dep-1);
}
int query(int x,int y,int val)
{
    int ret=0;
    for (int i=30;i>=0;i--)
    {
        int tmp=val&(1<<i);
        if (!tmp)
        {
            if (sz[rs[y]]-sz[rs[x]]!=0) ret+=(1<<i),x=rs[x],y=rs[y];
            else    x=ls[x],y=ls[y];
        }
        else
        {
            if (sz[ls[y]]-sz[ls[x]]!=0) ret+=(1<<i),x=ls[x],y=ls[y];
            else    x=rs[x],y=rs[y];
        }
    }
    return ret;
}
int main()
{
    in(n);in(m);size=(int)(sqrt(n));cnt=n/size+(bool)(n%size);
    for (int i=1;i<=n;i++)  in(a[i]),a[i]^=a[i-1];
    for (int i=1;i<=n;i++)  insert(root[i-1],root[i],a[i],30);
    for (int i=1;i<=cnt;i++)    for (int j=(i-1)*size+1;j<=n;j++)
    {
        f[i][j]=max(f[i][j-1],query(root[(i-1)*size],root[j],a[j]));
        if (i==1)   f[i][j]=max(f[i][j],a[j]);
    }
    while (m--)
    {
        int l,r;lastans%=n;in(l);in(r);l=(l+lastans)%n+1;r=(r+lastans)%n+1;
        if (l>r)    swap(l,r);l--;int t;lastans=t=0;
        for (int i=1;i<=cnt;i++)    if (l<=(i-1)*size+1&&r>=(i-1)*size+1)   {   lastans=f[i][r];t=i;break;  }
        if (t)
            for (int j=l;j<=(t-1)*size+1;j++)   lastans=max(lastans,query(root[l-1],root[r],a[j]));
        else
            for (int j=l;j<=r;j++)  lastans=max(lastans,query(root[l-1],root[r],a[j]));
        printf("%d\n",lastans);
    }
}

你可能感兴趣的:(分块,可持久化trie)