https://citel.bjtu.edu.cn/acm/problem/1951#submit
- 宇宙人浇花
时间限制 1000 ms 内存限制 256 MB
因为没见过飞船,则卷博士把宇宙人的飞船修成了小汽车,于是他们被迫留在了企鹅村。
失去目标的宇宙人没有变成咸鱼,他们很快找到了一份浇花的工作。
花园的花一字排开,每盆花都有一个美丽值,而整个花园的和谐度是所有花美丽值的异或和。
宇宙人只能浇连续的一段花,并且一天只能浇一次,每盆被浇到的花美丽值都会加 1。
花园主人琪琪想让今天花园的和谐度尽可能大,请问和谐度最大能达到多少?(如果浇水不能增大花园的和谐度,宇宙人可以不浇水)
输入数据
第一行是一个整数 n (1≤n≤10^5) ,表示花的盆数。
第二行是 n 个整数 a1,a2,…,an (1≤ai≤10^9) ,表示n盆花的美丽值。
输出数据
输出一个整数,即花园今天能达到的最大和谐度。
样例输入
5
4 5 2 3 1
样例输出
7
样例说明
宇宙人可以浇第 3 盆和第 4 盆花,浇完花后,这些花的美丽值变为 4 5 3 4 1 ,4⊕5⊕3⊕4⊕1=7 ,可以证明 7 是能得到的最大和谐度。
思路:
- 一段的连续异或可以用前缀异或来处理
- 对于连续修改,需要预处理前缀异或没有加的和加了的然后扔到字典树上去。
- 查询的时候查询a[i]^b[i]类似于把当前连续增加的一段先和b[i]抵消成0,然后再把a[i]给加回上去。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+1000;
typedef long long LL;
inline LL read(){
LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){
if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){
x=x*10+ch-48;ch=getchar();}
return x*f;}
LL tree[maxn][2],a[maxn],prea[maxn],preb[maxn],pt=0;
void ins(LL val){
LL cur=0;
for(LL i=31;i>=0;i--){
LL c=(val>>i)&1;
if(!tree[cur][c]) tree[cur][c]=++pt;
cur=tree[cur][c];
}
}
LL query(LL val){
LL res=0;LL cur=0;
for(LL i=31;i>=0;i--){
LL c=(val>>i)&1;
if(tree[cur][1^c]) {
res+=1LL<<i;
cur=tree[cur][1^c];
}
else{
res+=0;
cur=tree[cur][c];
}
}
return res;
}
int main(void){
cin.tie(0);std::ios::sync_with_stdio(false);
LL n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++){
prea[i]=prea[i-1]^a[i];
preb[i]=preb[i-1]^(a[i]+1);
}
LL ans=0;
for(int i=1;i<=n;i++){
LL x=(prea[n]^prea[i])^preb[i];
ins(x);
ans=max(ans,query(prea[i]^preb[i]));
}
cout<<ans<<endl;
return 0;
}