【GDOI2018模拟9.21】数列

(File IO): input:sequence.in output:sequence.out
Time Limits: 2000 ms Memory Limits: 262144 KB Detailed Limits

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample Input

5 5 0
3 1 2 9 4
1 5
4 4
1 4
1 3
2 5

Sample Output

3
4
15
11
3

Data Constraint
这里写图片描述

题解

首先这样的二进制题目一般都是用trie来解决的
设sum[i][j]=ai xor xi+1… xor xj
有sum[i][j]=sum[i][k] xor sum[k+1][j]
那么我们可以构一个可持久化trie,把前缀和都挂上去,那么每次询问就可以做到n log 级别
考虑分块
我们可以与处理一个an[x][y]表示 max(ed[y]t1=be[x]ed[y]t2=be[y]sum[t1][t2])
那么在算答案的时候我们只需要计算两端中至少有一个不在括住的完整的块里面的最大值了,复杂度 nnlogn 级别的了

贴代码

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fo1(i,b,a) for(i=b;i>=a;i--)
const int maxn=2e5+5,bl=155;

using namespace std;

int a[maxn],root[maxn],bb[maxn],ee[maxn],cc[30],sum[maxn];
int g[maxn][bl];
int be[bl],ed[bl],an[bl][bl];
int go[maxn*40][3];
int i,j,k,l,m,n,q,x,y,z,now,qu,tot,t1,t2,p,ans,t,r,ss;
bool bz;

void ge(int x,int y){
    int j;
    tot=0;
    fo1(j,29,0){
        if ((z & cc[j])>0) p=1; else p=0; p=p xor 1;
        if (go[go[x][p]][2]-go[go[y][p]][2]!=0){
            x=go[x][p]; y=go[y][p]; tot=tot+cc[j];
        } else{
            p=p xor 1;
            x=go[x][p]; y=go[y][p];
        }
    }
    if (bz) tot=max(tot,z);
}
int main(){
    freopen("sequence.in","r",stdin);
    freopen("sequence.out","w",stdout);
    scanf("%d%d%d",&n,&q,&t);
    cc[0]=1;
    fo(i,1,30) cc[i]=cc[i-1]*2;
    fo(i,1,n){
        scanf("%d",&a[i]);
        x=x xor a[i];
        sum[i]=x;
        root[i]=++now;
        y=root[i-1];
        z=root[i]; go[z][2]=i;
        fo1(j,29,0){
            if ((x & cc[j])>0){
                go[z][0]=go[y][0]; go[z][1]=++now; z=now; go[now][2]=go[go[y][1]][2]+1;
                y=go[y][1];
            } else{
                go[z][1]=go[y][1]; go[z][0]=++now; z=now; go[now][2]=go[go[y][0]][2]+1;
                y=go[y][0];
            }
        }
    }
    x=trunc(sqrt(n))-1;
    be[1]=1; ed[1]=1+x; y=1; z=1+x; bb[1]=1; ee[1+x]=1;
    while (z<=n){
        if (z+x>=n){
            be[y+1]=ed[y]+1;
            ed[y+1]=n; y++; bb[be[y]]=y; ee[ed[y]]=y; break;
        }
        be[y+1]=ed[y]+1; y++;
        ed[y]=be[y]+x;
        bb[be[y]]=y; ee[ed[y]]=y;
        z=ed[y];
    }
    qu=y;
    fo(i,1,qu){
        ans=0;
        fo1(j,i,1){
            fo(k,be[i],ed[i]){
                bz=false;
                y=root[k]; x=root[be[j]-1]; z=sum[k];
                if (be[j]>=2) x=root[be[j]-2]; else bz=true;
                ge(x,y);
                ans=max(ans,tot);
            }
            an[i][j]=ans;
        }
    }
    ans=0;
    fo(i,1,q){
        scanf("%d%d",&x,&y);
        x=(x+t*ans)%n+1;
        y=(y+t*ans)%n+1;
        l=min(x,y);
        r=max(x,y);
        x=l; y=r;
        while (y && ee[y]==0) y--;
        while (x<=n && bb[x]==0) x++;
        t1=bb[x]; t2=ee[y];
        ans=0;
        if (x>0 && y>0)
        while (t2>=t1){
            ans=max(ans,an[t2][t1]);
            t2--;
        }
        y=max(y,l);
        x=min(x,r);
        fo(j,y,r){
            z=sum[j];
            bz=false;
            ss=max(0,l-2); if (l==1) bz=true;
            ge(root[ss],root[j]);
            ans=max(ans,tot);
        }
        fo(j,l,x){
            bz=false;
            z=sum[j-1];
            ge(root[j-1],root[r]);
            ans=max(ans,tot);
        }
        printf("%d\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值