BZOJ2741: 【FOTILE模拟赛】L(分块+可持续化Trie)

传送门

题意:
求区间的最大子区间异或和。 (n12000)

题解:
首先计算前缀和转化为子区间求两两异或最大值。
看到 n <script type="math/tex" id="MathJax-Element-83">n</script>范围这么小,自然想到先分块搞搞了。。。
再套一颗可持续化Trie。。

#include<bits/stdc++.h>
using namespace std;
struct IO{
    streambuf *ib,*ob;
    inline void init(){
        ios::sync_with_stdio(false);
        cin.tie(NULL);cout.tie(NULL);
        ib=cin.rdbuf();ob=cout.rdbuf();
    }
    inline int read(){
        char ch=ib->sbumpc();int i=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-1;ch=ib->sbumpc();}
        while(isdigit(ch)){i=(i+(i<<2)<<1)+ch-'0';ch=ib->sbumpc();}
        return i*f;
    }
    inline void W(long long x){
        static int buf[50];
        if(!x){ob->sputc('0');ob->sputc('\n');return;}
        if(x<0){ob->sputc('-');x=-x;}
        while(x){buf[++buf[0]]=x%10;x/=10;}
        while(buf[0])ob->sputc(buf[buf[0]--]+'0');
        ob->sputc('\n');
    }
}io;

const int Maxn=2e4+50;
int n,m,S,lastans,nowval,a[Maxn],sumval[Maxn],bg[Maxn],ed[Maxn],tot,pos[Maxn],ans[400][Maxn];
const int Maxdep=31;

struct node{
    node *lc,*rc;
    int sze;
    inline void upt(){
        sze=lc->sze+rc->sze;
    }
}Pool[Maxn<<6],*pool=Pool,*null=Pool,*rt[Maxn];

inline node* newnode(){
    ++pool;
    pool->lc=pool->rc=null;
    return pool;
}

inline void insert(node *x,node *&y,int dep,int val){
    y=newnode();y->lc=x->lc;y->rc=x->rc;y->sze=x->sze+1;
    if(!dep)return;
    if(val&(1<<(dep-1)))insert(x->rc,y->rc,dep-1,val);
    else insert(x->lc,y->lc,dep-1,val);
}
inline int query(node *x,node *y,int dep,int val,int &t){
    if(!dep)return t;
    if(val&(1<<(dep-1))){
        if(y->lc->sze-x->lc->sze)return query(x->lc,y->lc,dep-1,val,t);
        else {t|=(1<<(dep-1));return query(x->rc,y->rc,dep-1,val,t);}
    }
    else{
        if(y->rc->sze-x->rc->sze){t|=(1<<(dep-1));return query(x->rc,y->rc,dep-1,val,t);}
        else return query(x->lc,y->lc,dep-1,val,t);
    }
}
int main(){
    io.init();n=io.read(),m=io.read();S=sqrt((double)n)+1;null->lc=null->rc=null;
    for(int i=0;i<=n+1;i++)rt[i]=null;
    insert(rt[0],rt[1],Maxdep,0);
    for(int i=1;i<=n;i++){
        a[i]=io.read();sumval[i]=sumval[i-1]^a[i];
        insert(rt[i],rt[i+1],Maxdep,sumval[i]);
    }
    for(int i=1;i<=n;i+=S){
        ++tot;bg[tot]=i;ed[tot]=min(i+S-1,n);
        for(int j=bg[tot];j<=ed[tot];j++){
            pos[j]=tot;
        }
    }
    for(int i=1;i<=tot;i++){
        if(bg[i]==n)break;
        ans[i][bg[i]+1]=sumval[bg[i]]^sumval[bg[i]+1];
        for(int j=bg[i]+2;j<=n;j++){
            int t=0;
            ans[i][j]=max(ans[i][j-1],sumval[j]^query(rt[bg[i]],rt[j],Maxdep,sumval[j],t));
        }
    }
    for(int i=1;i<=m;i++){
        int l=(1ll*io.read()+lastans)%n+1,r=(1ll*io.read()+lastans)%n+1;
        if(l>r)swap(l,r);l--;
        if(r-l+1<2*S){
            lastans=sumval[l]^sumval[l+1];
            for(int j=l+2;j<=r;j++){
                int t=0;
                lastans=max(lastans,sumval[j]^query(rt[l],rt[j],Maxdep,sumval[j],t));
            }
        }
        else{
            int L=((l&&l==bg[pos[l]])?(pos[l]):(pos[l]+1));
            lastans=ans[L][r];
            for(int j=l;j<bg[L];j++){
                int t=0;
                lastans=max(lastans,sumval[j]^query(rt[j+1],rt[r+1],Maxdep,sumval[j],t));
            }
        }
        io.W(lastans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值