Description
给出一个长度为n的序列。
求出l1,r1,l2,r2,使得a[l1]^a[l1+1]…a[r1]+a[l2]^a[l2+1]…a[r2]最大,且1 <= l1 <= r1 < l2 <= r2 <= n
Sample Input
5
1 2 3 1 2
Sample Output
6
这道题是01字典树的版题,你就用一个数的二进制从最高位建字典树,且保留前导0.
然后我们维护两个数组,lmax[i]表示1~i这一区间l~r异或和的最大值,rmax[i]即反之。
先考虑求lmax,我们考虑按顺序建01字典树,对于当前的一个r,如果当前最高位为hh,当前的x如果存在hh^1这个孩子,肯定考虑,往hh^1这个孩子走,这样求即可。
rmax反之。。。
#include <cstdio>
#include <cstring>
using namespace std;
int _max(int x, int y) {return x > y ? x : y;}
struct trnode {
int c[2];
} t[30 * 410000]; int cnt;
int a[410000], lmax[410000], rmax[410000];
void clean(int u) {
t[u].c[0] = t[u].c[1] = 0;
}
void Link(int d) {
int x = 0;
for(int i = 30; i >= 0; i--) {
int hh = 0;
if(d >= (1 << i)) hh = 1, d -= (1 << i);
if(!t[x].c[hh]) clean(cnt + 1), t[x].c[hh] = ++cnt;
x = t[x].c[hh];
}
}
int query(int d) {
int x = 0, ans = 0;
for(int i = 30; i >= 0; i--) {
int hh = 0;
if(d >= (1 << i)) hh = 1, d -= (1 << i);
if(t[x].c[hh ^ 1]) ans += (1 << i), x = t[x].c[hh ^ 1];
else x = t[x].c[hh];
}
return ans;
}
int main() {
int n; scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
cnt = 0; clean(0); Link(0);
int now = 0;
for(int i = 1; i <= n; i++) {
now ^= a[i]; Link(now);
int yy = query(now);
lmax[i] = _max(lmax[i - 1], yy);
}
cnt = 0; clean(0); Link(0);
now = 0;
for(int i = n; i >= 1; i--) {
now ^= a[i]; Link(now);
int yy = query(now);
rmax[i] = _max(rmax[i + 1], yy);
}
int ans = 0;
for(int i = 0; i <= n; i++) ans = _max(ans, lmax[i] + rmax[i + 1]);
printf("%d\n", ans);
return 0;
}