bzoj2741: 【FOTILE模拟赛】L

分块+可持久化Trie

取前缀和,然后搞出每个块之间的答案,不在一个块的就暴力在Trie找

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;

struct Trie
{
    int w[2],c;
    Trie(){w[0]=w[1]=0,c=0;}
}tr[11000000];int trlen,rt[13000];
int insert(int now,int d)
{
    if(now==0)now=++trlen;
    int ret=now;
    for(int i=30;i>=0;i--)
    {
        int x=(((1<<i)&d)>0);
        if(tr[now].w[x]==0)
            tr[now].w[x]=++trlen;
        now=tr[now].w[x];
        tr[now].c++;
    }
    return ret;
}
int merge(int x,int y)
{
    if(x==0||y==0)return x+y;
    tr[x].c+=tr[y].c;
    tr[x].w[0]=merge(tr[x].w[0],tr[y].w[0]);
    tr[x].w[1]=merge(tr[x].w[1],tr[y].w[1]);
    return x;
}
int getmax(int x,int y,int d)
{
    int ret=0;
    for(int i=30;i>=0;i--)
    {
        int k=((((1<<i)&d)>0)^1);
        if(tr[tr[y].w[k]].c-tr[tr[x].w[k]].c>0)
        {
            ret+=(1<<i);
            x=tr[x].w[k],y=tr[y].w[k];
        }
        else x=tr[x].w[k^1],y=tr[y].w[k^1];
    }
    return ret;
}

int s[13000];
int block,st[13000];
int f[150][150];
int main()
{
    freopen("L.in","r",stdin);
    freopen("L.out","w",stdout);
    int n,Q,x;
    scanf("%d%d",&n,&Q);
    s[1]=0;
    for(int i=1;i<=n;i++)
        scanf("%d",&x), s[i+1]=s[i]^x;
        
    trlen=0;memset(rt,0,sizeof(rt));
    for(int i=1;i<=n+1;i++)
    {
        rt[i]=insert(rt[i],s[i]);
        rt[i]=merge(rt[i],rt[i-1]);
    }
    
    block=(int(sqrt(double(n+1))))+1;
    for(int i=1;i<=n+1;i++)st[i]=(i-1)/block+1;
    for(int i=1;i<=block;i++)
    {
        int mx=0,j=i,be=(i-1)*block+1;
        for(int k=be;k<=n+1;k++)
        {
            if(st[k-1]!=st[k]&&k!=be)
            {
                f[i][j]=mx;
                j++;
            }
            mx=max(mx,getmax(rt[be-1],rt[k],s[k]));
        }
        f[i][j]=mx;
    }
    
    int l,r,ans=0;
    while(Q--)
    {
        scanf("%d%d",&l,&r);
        l=( (LL(l))+(LL(ans)) )%n+1;
        r=( (LL(r))+(LL(ans)) )%n+1;
        if(l>r)swap(l,r);
        
        r++;
        ans=0;
        if(st[l]==st[r])
        {
            for(int i=l;i<=r;i++)
                ans=max(ans,getmax(rt[l-1],rt[r],s[i]));
        }
        else
        {
            if(st[l]+1<=st[r]-1)ans=f[st[l]+1][st[r]-1];
            
            for(int i=l;i<=st[l]*block;i++)
                ans=max(ans,getmax(rt[l-1],rt[r],s[i]));
                
            for(int i=(st[r]-1)*block+1;i<=r;i++)
                ans=max(ans,getmax(rt[l-1],rt[r],s[i]));
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-08-08 16:23  AKCqhzdy  阅读(105)  评论(0编辑  收藏  举报