zoukankan      html  css  js  c++  java
  • 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
    ",l,r);
            last=GetAns(l,r);
            printf("%d
    ",last);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Python自动化开发
    Python自动化开发
    Python自动化开发
    前端开发
    keepalived和zookeeper对比
    网页静态化—redis | freemarker
    redis学习笔记
    消息队列—ActiveMQ
    Zookeeper原理架构
    Zookeeper集群搭建
  • 原文地址:https://www.cnblogs.com/wust-ouyangli/p/5752083.html
Copyright © 2011-2022 走看看