表示数组前 个数的异或和,就是区间的异或和
那如果想知道以 位置结尾的子数组的最大异或和,只需要知道 中的数异或的最大值就可以了。
(即这些区间异或和的最大值)
那怎么样快速地知道 中的数异或和的最大值呢?
我们利用前缀树的结构,对每一个,从最高位到最低位判断。这里需要注意一下,因为我们想让异或和最大,所以我们希望符号位是0,即异或出的数值是正数,然后其他位置我们期望数值为1
所以对于最高位来说,我们希望和的这一位相同,其他位置我们希望和的这一位不同。
走完前缀树以后,就维护出了以位置结尾的子数组的最大异或和,然后把当前的数加到前缀树里。

#include<iostream>
using namespace std;
struct node;
struct node{
    node* num[2];
};
node * head;
void add(int num){//把num加到前缀树里
    node * now = head;
    for(int i = 31 ; i >= 0 ; i--){
        int t = 1&(num>>i);//取num的第i位
        if(now->num[t] == NULL){
            now->num[t] = new node{NULL,NULL};
            now = now->num[t];
        }
        else{now = now->num[t];}
    }
}
const int MAXN = 1e5+10;
int main(){
    int n; cin >> n;
    int XOR[MAXN]={0};
    for(int i =1 ; i <= n ; i++){//求前缀异或和
        int t; cin >>t;
        XOR[i] = t^XOR[i-1];
    }
    head = new node{NULL,NULL};
    node * now = head;
    add(XOR[1]);
    int maxn = XOR[1];
    for(int i = 2 ; i <= n ; i++){
        now = head;
        int ans = 0;
        for(int j = 31 ; j >= 0 ; j--){
            int t = 1&(XOR[i]>>j);
            int target= !t;//希望和0还是和1异或
            if(j == 31){target = t;}
            if(now->num[target]!=NULL){
                now=now->num[target]; 
                ans=ans|((target^t)<<j); 
            }
            else{
                 now = now->num[!target];
                 ans=ans|((!target^t)<<j);
            }
        }
        add(XOR[i]);
        maxn = max(maxn,ans);
    }
    cout<<maxn<<endl;
    return 0;
}