字典树处理《异或》

题目:
问题很简单,现在有一个数组a1,a2,a3……an。你的任务就是找到一个连续子段[l,r],使得al^al+1^……^ar达到最大。
Input
多组输入,每组有两行。第一行有一个整数n(1<=n<=10^5),表示数组的元素个数。第二行有n个元素,依次表示数组的元素。(0<=ai<=10^6)
Output
每组输出一行,这行仅一个数字。表示最大的连续子段异或值。
Sample Input
Raw
5
1 2 3 4 5
5
2 3 2 3
      初次接触字典树,看了很多大神的代码,因为我根本不知道为什么字典树可以处理异或,现在有了一点点理解所以写一下博客强化一下记忆。
题目分析
       首先要明白异或是什么,异或就是相对于二进制的一种运算,相同为0,不同为1;
       对于这道题我们先处理一个前缀,即1~2,1~3,~~~~,1~n,的异或值;对于l~~r区间的异或值就为1~~r的异或值在异或1~~l-1的异或值;现在这个问题就变成了在前缀数组里找两个数求他们异或值得 最大;
       因为每一位只有0,1,两种状态,所以就像一个二叉,我们题目的数据范围为10^4所以25位就可以了,我们先建立一个字典树,当我们对字典树进行访问时就对答案进行比较看谁最大,我们从最高位进行判断,如果最高位有不同(相同1,不同0)的那么这个答案肯定是最优的,我们再进行判断下一位,如果最高位相同我们就直接判断下一位,又看看下一位是否相同,或者不同,下面代码判断相同不同我用的bool类型如果有不同的话,我肯定是建立了节点的 如果相同就找不到!k这个节点。
       废话多都说了,上码。
AC代码

#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;

int a[100005];
int tree[1000005][2];
int clk=0;

void add(int qq)
{
    int i,len=25,rt=0;
    bool k;
    for (i=len;i>=0;i--)
    {
        k=qq&(1<<i);
        if(!tree[rt][k])
            tree[rt][k]=++clk;
        rt=tree[rt][k];
    }
}

int que(int qq)
{
    int rt=0,len=25,i;
    int an=0;
    bool k;
    for (i=len;i>=0;i--)
    {
        k=qq&(1<<i);
        if(tree[rt][!k])
        {
            an=an+(1<<i);
            rt=tree[rt][!k];
        }
        else
            rt=tree[rt][k];
    }
    return an;
}

int main ()
{
    int n,i,k;
    while (scanf ("%d",&n)!=EOF)
    {
        memset(tree,0,sizeof(tree));
        clk=0; int ans=0;
        scanf ("%d",&a[0]);
        for (i=1;i<n;i++)
        {
            scanf ("%d",&k);
            a[i]=k^a[i-1];
        }
        add(0);
        for (i=0;i<n;i++)
        {
            add(a[i]);
            int maxn=que(a[i]);
            ans=max(ans,maxn);
        }
        printf ("%d\n",ans);
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值