bzoj2741(分块+可持久化Trie)

题意中文我就不说了

解析: 分块+可持久化Trie,先得到前缀异或值,插入到Trie中,然后分块,对每一块,处理出dp[i][j](i代表第几块,j代表第几个位置),dp[i][j]代表以第i块开始的到j这个位置

的连续字串最大异或值。查询时,如果l,r不在同一块内,可以先查询l所在的块的后一个块到r的连续字串最大异或值,之前的dp就可以派上用场了,然后就是处理l到l所在块

的这段区间,取两者最大值即可。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=12005;
const int maxbit=31;
int N,M,A[maxn];
int tr[maxn];
struct PerTrie
{
    int next[10000005][2],num[10000005];
    int id;
    void init(){ id=next[0][0]=next[0][1]=num[0]=0; }
    int f(int x,int i){ return (x>>i)&1; }
    void Insert(int& rt,int pre,int x,int pos) //插入
    {
        rt=++id;
        next[rt][0]=next[pre][0];
        next[rt][1]=next[pre][1];
        num[rt]=num[pre]+1;
        if(pos==-1) return;
        int d=f(x,pos);
        Insert(next[rt][d],next[pre][d],x,pos-1);
    }
    int MaxXor(int l,int r,int x) //查询最大异或值,因为A[i]保存
    {                             //的是前缀异或值,所以得到的结果就是某一段区间的异或值
        int ret=0;
        for(int i=maxbit;i>=0;i--)
        {
            int d=f(x,i);
            int a=next[l][d^1],b=next[r][d^1];
            if(num[b]-num[a]>0) ret|=(1<<i),l=a,r=b;
            else l=next[l][d],r=next[r][d];
        }
        return ret;
    }
}PT;
int block,num,bel[maxn],dp[120][maxn]; //dp保存第几块到第几个数的区间最大异或值
void init()
{
    tr[0]=0;
    PT.init();
    for(int i=1;i<=N;i++) PT.Insert(tr[i],tr[i-1],A[i],maxbit); //插入
    block=(int)sqrt(N+0.5);
    num=N/block;
    if(N%block) num++; //加1
    memset(dp,0,sizeof(dp));
    bel[0]=0;
    for(int i=1;i<=N;i++) bel[i]=(i-1)/block+1; //记录下属于哪个块
    for(int i=1;i<=num;i++)
    {
        int st=(i-1)*block+1;
        for(int j=st;j<=N;j++)
        {
            dp[i][j]=max(dp[i][j-1],A[j]^A[st-1]); //可能是[st,j]这段区间
            dp[i][j]=max(dp[i][j],PT.MaxXor(tr[st-1],tr[j],A[j])); //再找最大的
        }
    }
}
int GetAns(int l,int r)
{
    l--;
    int s=bel[l],ret=0;
    if(bel[r]>s) ret=dp[s+1][r]; //查询从后面一个块开始的
    for(int i=l;i<=min(r,s*block);i++)
    {
        ret=max(ret,PT.MaxXor(tr[l-1],tr[r],A[i]));
    }
    return ret;
}
int main()
{
    scanf("%d%d",&N,&M);
    A[0]=0;
    int x;
    for(int i=1;i<=N;i++)
    {
        scanf("%d",&x);
        A[i]=A[i-1]^x;
    }
    init();
    int last=0,l,r;
    while(M--)
    {
        scanf("%d%d",&l,&r);
        l=(l+(LL)last)%N+1;
        r=(r+(LL)last)%N+1;
        if(l>r) swap(l,r);
        //printf("%d %d\n",l,r);
        last=GetAns(l,r);
        printf("%d\n",last);
    }
    return 0;
}
View Code

 

posted @ 2016-08-09 10:28  wust_ouyangli  阅读(136)  评论(0编辑  收藏  举报