bzoj Codechef REBXOR HYSBZ - 4260 (01字典树 求两个异或区间的和的最大值)

本文介绍了一种解决区间异或最大值问题的算法,利用01字典树维护前缀和后缀的最大异或值,通过巧妙地插入和查询操作实现高效求解。

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

Input
输入数据的第一行包含一个整数N,表示数组中的元素个数。
第二行包含N个整数A1,A2,…,AN。

Output
输出一行包含给定表达式可能的最大值。

Sample Input 51 2 3 1 2
Sample Output 6Hint

满足条件的(l1,r1,l2,r2)有:(1,2,3,3),(1,2,4,5),(3,3,4,5)。

对于100%的数据,2 ≤ N ≤ 4*105,0 ≤ Ai ≤ 109。

题意: 很清楚。

思路: 维护一个前缀, qian[i]  表示到第i 位的区间异或的最大值。 同理,维护一个后缀。 那么答案就是后缀+前缀。 维护的时候用01字典树来维护。

另外,这个题真的好卡时间呀。。。 从32 开始就不可以竟然。   可怕。

代码:

#include<bits/stdc++.h>

using namespace std;

#define Memset(x, a) memset(x, a, sizeof(x))
typedef long long ll;
const int maxn = 400000 + 5;//集合中的数字个数
int ch[32*maxn][2];         //节点的边信息
ll val[32*maxn];            //节点存储的值
int sz;                     //树中当前节点个数
int num[32*maxn];           // 出现的次数

void init(){
    Memset(ch[0],0);           //树清空
    memset(num,0,sizeof(num));
    sz=1;
}

void _insert(ll a){//在字典树中插入 a
                  //和一般字典树的操作相同 将X的二进制插入到字典树中
    int rt=0;
    for(int i=31;i>=0;i--){
        int c=((a>>i)&1);
        if(!ch[rt][c]){
            Memset(ch[sz],0);
            val[sz]=0;
            num[sz]=0;
            ch[rt][c]=sz++;
        }
        rt=ch[rt][c];
        num[rt]++;
    }
    val[rt]=a;     //最后的节点插入value
}

ll query(ll a){   //在字典树中查找和a异或的值最大的元素b 返回b的值
    int rt=0;
    for(int i=31;i>=0;i--){
        int c=((a>>i)&1);
        if(ch[rt][c^1]&&num[ch[rt][c^1]]) rt=ch[rt][c^1];//c=0,b=c^1=1,b^c=1;c=1,b=c^1=0,b^c=1;
        else rt=ch[rt][c];
    }
    return a^val[rt];
}


void update(ll a,int d)
{
    int rt=0;
    for(int i=31;i>=0;i--)
    {
        int c=((a>>i)&1);
        rt=ch[rt][c];
        num[rt]+=d;
    }
    return ;
}

const int N=4e5+5;
ll a[N];
ll qian[N];
ll hou[N];
int n;

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
    init();
    ll x=0;
    _insert(0);
    for(int i=1;i<=n;i++){
        x=x^a[i];
        //printf("%lld\n",x);
        _insert(x);
        qian[i]=query(x);
        //printf("qian : %lld\n",qian[i]);
        qian[i]=max(qian[i],qian[i-1]);
    }

    init();
    ll ans=-1;
    x=0;
    _insert(0);
    for(int i=n;i>=1;i--){
        x=x^a[i];
        _insert(x);
        hou[i]=query(x);
        hou[i]=max(hou[i],hou[i+1]);
        ans=max(ans,qian[i-1]+hou[i]);
    }

    printf("%lld\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值