【bzoj3261】最大异或和
Description
Input
Output
Sample Input
5 5
2 6 4 3 6
A 1
Q 3 5 4
A 4
Q 5 7 0
Q 3 6 6
对于测试点 1-2,N,M<=5 。
2 6 4 3 6
A 1
Q 3 5 4
A 4
Q 5 7 0
Q 3 6 6
对于测试点 1-2,N,M<=5 。
Sample Output
4
5
6
5
6
HINT
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int a[maxn],b[maxn];
struct Node{
int sum;
int l;
int r;
Node(){
l=0,r=0,sum=0;
}
}node[maxn<<5];
int root[maxn],cnt,K=5,n,m;//K表示該題的数据范围的对应二进制的位数
char ch[10];
int update(int last,int val){
int now = ++cnt;//cnt表示的是该节点的标号
node[now] = node[last];//一开始的的时候新版本的根节点指向上一个版本的根节点
int temp = now;
for(int i=K;i>=0;i--){
int bit = (val>>i)&1;
if(bit){
node[temp].l = node[last].l;//左边的不去修改,一直复制上一个版本的信息即可
node[temp].r = ++cnt;//当前版本中该位置需要有更新所以新建节点
temp = node[temp].r, last = node[last].r;
node[temp].sum = node[last].sum+1;//不能是自己++ 需要保持与上一个版本的信息一致 所以在上一个版本基础上++
}
else{//该位是0 往左走
node[temp].r = node[last].r;
node[temp].l = ++cnt;
temp = node[temp].l, last = node[last].l;
node[temp].sum = node[last].sum+1;
}
}
return now;//返回当前版本的根节点的标号
}
int query(int pre, int now,int val){
int ans = 0;
for(int i=K;i>=0;i--){
int bit = (val>>i)&1;
if(bit){//当前位置是1 则需要异或0 可以得到max 所以往左走
if(node[now].l==0){//左节点没有 往又走
now = node[now].r;
pre = node[pre].r;
continue;
}
int count = node[node[now].l].sum - node[node[pre].l].sum;//当前版本与之前版本的个数差
if(count>0){
ans += (1<<i);
now = node[now].l;
pre = node[pre].l;
}
else{
now = node[now].r;
pre = node[pre].r;
}
}
else{//当前位是0 需要异或1得到最大
if(node[now].r==0){//右节点没有 往左走
now = node[now].l;
pre = node[pre].l;
continue;
}
int count = node[node[now].r].sum - node[node[pre].r].sum;//当前版本与之前版本的个数差
if(count>0){
ans += (1<<i);
now = node[now].r;
pre = node[pre].r;
}
else{
now = node[now].l;
pre = node[pre].l;
}
}
}
return ans;
}
void init(){
cnt = 0;//每一次都需要重置0的个数
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(root,0,sizeof(root));
}
int main(){
while(~scanf("%d%d",&n,&m)){
// n++;
// root[1] = update(root[0],0);//一开始要插入为0 因为最初异或和是0
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i] = b[i-1]^a[i];
root[i] = update(root[i-1],b[i]);
// printf("%d\n",root[i]);
}
for(int i=1;i<=m;i++){
scanf("%s",ch);
if(ch[0] == 'A'){
n+=1;
scanf("%d",&a[n]);
b[n] = b[n-1]^a[n];
root[n] = update(root[n-1],b[n]);
}
else{
int l,r,x;
scanf("%d%d%d",&l,&r,&x);//因为题目中需要求a[i]^..a[n]^x 最大
//我们将b[n]作为记录a[1]^..a[n]的前缀和 所以要求该式子 我们只需要求 b[i-1]^b[n]^x 最大即可
//所以我们要定位i-1 且 l<=i<=r 所以 l-1<=i-1<=r-1 因此在下面的区间搜寻即可
int ans = query(root[l-2],root[r-1],x^b[n]);
printf("%d\n",ans);
}
}
}
}