BZOJ 3261 最大异或和(可持久化trie)

本文介绍了如何使用可持久化Trie数据结构解决一个关于最大异或和的问题。题目要求在给定的非负整数序列上进行添加元素和区间询问最大异或和的操作。通过分析,可以利用可持久化Trie进行贪心查找以高效地处理这些操作。文章包含了题目的详细描述、问题分析以及递归和非递归的解决方案代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目大意

给定一个非负整数序列{a},初始长度为N。
有M个操作,有以下两种操作类型:
1、Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。
2、Qlrx:询问操作,你需要找到一个位置p,满足l<=p<=r,使得:
a[p] xor a[p+1] xor … xor a[N] xor x 最大,输出最大是多少。

范围是3e5

分析

带区间的二进制trie,但是没有修改,只是在末尾加入,所以直接可持久化二进制trie贪心查找即可。

我也不知道为什么这么慢,但是我知道了递归和非递归时间差不多。

代码

递归和非递归都在里面了。

#include<set>
#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<vector>
#include<cstdio>
#include<cctype>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=3e5+1005,N=24,maxv=maxn*2*N;
namespace IStream{  
    const int L=1<<15;  
    char buffer[L],*S,*T;  
    inline char Get_Char()  
    {  
        if(S==T)  
        {  
            T=(S=buffer)+fread(buffer,1,L,stdin);  
            if(S==T) return EOF;  
        }  
        return *S++;  
    }  
    inline void Rd(int &re) 
    {  
        char c; 
        re=0;
        int k=1;
        for(c=Get_Char();(c<'0'||c>'9') && c!='-';c=Get_Char());  
        if(c=='-')c=Get_Char(),k=-1;
        while(c>='0'&&c<='9')  
            re=(re<<1)+(re<<3)+(c-'0'),c=Get_Char();  
        re*=k;
    } 
    inline void Rd(char *s)
    {
        char c;
        int len=0;
        for(c=Get_Char();c<'A'||c>'z';c=Get_Char()); 
        while(c!=' ' && c!='\n')
            s[len++]=c,c=Get_Char();
    }
    int t[20],sz;
    inline void outs(int x)
    {
        sz=0;
        do{
            t[++sz]=x%10;
            x/=10;
        }while(x);
        for(int i=sz;i;i--)putchar(t[i]^48);
        putchar('\n');
    }
}
struct TRIE
{
    int rt[maxv],np,ch[maxv][2],sz[maxv],val[maxv];
    void Build()
    {
        np=1;
        memset(rt,0,sizeof(rt));
        memset(ch,0,sizeof(ch));
        memset(sz,0,sizeof(sz));
        memset(val,0,sizeof(val));
        rt[0]=1;
    }
    int Newnode(int pre)
    {
        ++np;
        if(pre)
            ch[np][0]=ch[pre][0],ch[np][1]=ch[pre][1],sz[np]=sz[pre],val[np]=val[pre];
        else
            ch[np][0]=ch[np][1]=sz[np]=val[np]=0;
        return np;
    }
    void add(int pre,int &now,int x,int i)
    {
        now=Newnode(pre);
        sz[now]++;
        if(i>N)
        {
            val[now]++;
            return;
        }
        bool id=x&(1<<(N-i));
        add(ch[pre][id],ch[now][id],x,i+1);
    }
    void add(int x,int c)
    {
        //cout<<x<<endl;
        int pre=rt[c-1];
        int now=rt[c]=Newnode(pre);
        for(int i=1;i<=N;i++)
        {
            bool id=x&(1<<(N-i));
            ch[now][id]=Newnode(ch[pre][id]);
            sz[ch[now][id]]++;
            now=ch[now][id];
            pre=ch[pre][id];
        }
        val[now]++;
    }
    int query(int lnow,int rnow,int x,int i)
    {
        if(i>N)return 0;
        bool id=x&(1<<(N-i));
        int ret;
        if(sz[ch[rnow][id^1]]-sz[ch[lnow][id^1]])
        {
            ret=query(ch[lnow][id^1],ch[rnow][id^1],x,i+1);
            ret=ret|(1<<(N-i));
        }
        else
        {
            ret=query(ch[lnow][id],ch[rnow][id],x,i+1);
            ret=ret&(~(1<<(N-i)));
        }
        return ret;
    }
    int query(int x,int l,int r)
    {
        //cout<<x<<endl;
        int lnow=rt[l],rnow=rt[r];
        for(int i=1;i<=N;i++)
        {
            bool id=x&(1<<(N-i));
            if(sz[ch[rnow][id^1]]-sz[ch[lnow][id^1]])
            {
                x=x|(1<<(N-i));
                rnow=ch[rnow][id^1];
                lnow=ch[lnow][id^1];
            }
            else
            {
                x=x&(~(1<<(N-i)));
                rnow=ch[rnow][id];
                lnow=ch[lnow][id];
            }

        }
        return x;
    }
}tri;
int n,m;
int sum[maxv];
char s[5];
void Init()
{
    int x;
    IStream::Rd(n);IStream::Rd(m);
    tri.Build();
    for(int i=1;i<=n;i++)
    {
        IStream::Rd(x);
        sum[i]=sum[i-1]^x;
        tri.add(tri.rt[i-1],tri.rt[i],sum[i-1],1);
    }
}
void solve()
{
    int x,l,r;
    while(m--)
    {
        IStream::Rd(s);
        if(s[0]=='A')
        {
            n++;
            IStream::Rd(x);
            sum[n]=sum[n-1]^x;
            tri.add(tri.rt[n-1],tri.rt[n],sum[n-1],1);
        }
        else
        {
            IStream::Rd(l);IStream::Rd(r);IStream::Rd(x);
            IStream::outs(tri.query(tri.rt[l-1],tri.rt[r],x^sum[n],1));
        }
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    Init();
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值