jzoj5382 [GDOI2018模拟9.21]数列 可持久化trie+分块

16 篇文章 0 订阅
6 篇文章 0 订阅

Description


这里写图片描述
n,q<=20000
a[i]<=10^9

Solution


今天场外体验noi刺激战场,发现我只会做T1这种送分题(⊙ˍ⊙),还没切。果然人菜还是要多读书

首先做前缀和,变成两个点的问题
与异或相关可以考虑trie。一个暴力的做法就是建可持久化trie然后枚举查询最大异或和
看到n很小一个想法就是对区间分块,预处理f[i,j]表示块i的起点到j这一段的答案,然后搞搞就可以了

如果没有强制在线可以莫队,然鹅直接莫队就有90分

Solution


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)

typedef long long LL;
const int N=20005;
const int B=185;

int rec[N*60][2],root[N],sum[N*60],tot;
int st[B],ed[B],bel[N],a[N];
int wjp[B][N],ans;

int read() {
    int x=0,v=1; char ch=getchar();
    for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
    for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
    return x*v;
}

int ins(int x,int v) {
    int y=++tot; int ret=y;
    drp(i,29,0) {
        rec[y][0]=rec[x][0];
        rec[y][1]=rec[x][1];
        sum[y]=sum[x]+1;
        int now=(v&(1<<i))!=0;
        x=rec[x][now];
        y=rec[y][now]=++tot;
    }
    sum[y]=sum[x]+1;
    return ret;
}

int query(int pre,int x,int v) {
    int ret=0;
    drp(i,29,0) {
        int now=(v&(1<<i))!=0;
        if (sum[rec[x][!now]]-sum[rec[pre][!now]]>0) {
            x=rec[x][!now];
            pre=rec[pre][!now];
            ret+=1<<i;
        } else {
            x=rec[x][now];
            pre=rec[pre][now];
        }
        // if (ret+(1<<i+1)-1<=ans) return ret;
    }
    return ret;
}

int main(void) {
    freopen("data.in","r",stdin);
    freopen("myp.out","w",stdout);
    int n=read(),q=read(),t=read();
    int m=sqrt(n);
    root[0]=ins(0,0);
    rep(i,1,n) {
        a[i]=a[i-1]^read();
        root[i]=ins(root[i-1],a[i]);
        bel[i]=(i-1)/m+1;
        if (!st[bel[i]]) st[bel[i]]=i;
        ed[bel[i]]=std:: max(ed[bel[i]],i);
    }
    rep(i,1,m) {
        rep(j,st[i],n) {
            wjp[i][j]=std:: max(wjp[i][j-1],query((st[i]-1)?root[st[i]-2]:0,root[j],a[j]));
        }
    }
    for (int lastans=0,cnt=0;q--;cnt++) {
        int l=read(),r=read(); ans=0;
        int x=(l+t*(LL)lastans)%n+1;
        int y=(r+t*(LL)lastans)%n+1;
        if (x>y) std:: swap(x,y);
        int px=bel[x],py=bel[y];
        if (py==px) {
            rep(j,x,y) ans=std:: max(ans,query((x-1)?(root[x-2]):0,root[y],a[j]));
        } else {
            ans=wjp[px+1][y];
            rep(j,x-1,ed[px]) ans=std:: max(ans,query((x-1)?(root[x-2]):0,root[y],a[j]));
            rep(j,st[py],y) ans=std:: max(ans,query((x-1)?(root[x-2]):0,root[y],a[j]));
        }
        printf("%d\n", ans); lastans=ans;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值