蓝书(算法竞赛进阶指南)刷题记录——BZOJ3261最大异或和(可持久化0-1 Trie)

题目:BZOJ3261.
题目大意:给定一个长度为 n n n的序列 a a a,支持两种操作:
1.在序列尾插入一个数字.
2.求一个在区间 [ l , r ] [l,r] [l,r]内的 p p p使得 a [ p ]   x o r   a [ p + 1 ]   x o r   . . .   x o r   a [ n ]   x o r   x a[p]\,xor\,a[p+1]\,xor\,...\,xor\,a[n]\,xor\,x a[p]xora[p+1]xor...xora[n]xorx最大,并输出这个值.
设操作次数为 m m m,则 1 ≤ n , m ≤ 3 ∗ 1 0 5 1\leq n,m\leq 3*10^5 1n,m3105.

考虑将原序列 a a a的前缀异或数组 s s s写出来,那么要求最大的值为:
a [ p ]   x o r   a [ p + 1 ]   x o r   . . .   x o r   a [ n ] = s [ p − 1 ]   x o r   s [ n ]   x o r   x a[p]\,xor\,a[p+1]\,xor\,...\,xor\,a[n]=s[p-1]\,xor\,s[n]\,xor\,x a[p]xora[p+1]xor...xora[n]=s[p1]xors[n]xorx.

发现这个式子中 s [ n ]   x o r   x s[n]\,xor\,x s[n]xorx是确定的,我们只需要求出最优的 s [ p − 1 ] s[p-1] s[p1]即可.

考虑没有区间限制时,这道题就可以直接用0-1 Trie维护异或的套路来做.

再考虑有区间限制时,将0-1 Trie换成可持久化0-1 Trie即可.可持久化0-1 Trie的实现与可持久化线段树类似,不再赘述.

代码如下(为了方便处理,我往第 1 1 1个节点前加了一个数即第 2 2 2棵树对应第 1 1 1个串):

#include<bits/stdc++.h>
  using namespace std;

#define Abigail inline void
typedef long long LL;

const int N=300000,C=25;

char rc(){
  char c=getchar();
  while (c<'A'||c>'Z') c=getchar();
  return c;
}

struct Trie{
  int s[2],cnt;
}tr[N*(C+2)*2+9];
int rot[N*2+9],cr,cn;

void Build(){cr=cn=0;}

/*void Insert(int a){
  tr[++cn]=tr[cr];rot[++cr]=cn;
  int x=rot[cr],x0=rot[cr-1];
  for (int i=C;i>=0;--i){
    ++tr[x].cnt;
    tr[++cn]=tr[tr[x0].s[a>>i&1]];
    tr[x].s[a>>i&1]=cn;
    x=cn;
    x0=tr[x0].s[a>>i&1];
  }
  ++tr[x].cnt;
}*/ 

void Insert(int a){ 
  rot[++cr]=++cn;
  int x=rot[cr],x0=rot[cr-1];
  for (int i=C;i>=0;--i){
  	tr[x]=tr[x0];++tr[x].cnt; 
  	tr[x].s[a>>i&1]=++cn;x=cn;
  	x0=tr[x0].s[a>>i&1];
  }
  tr[x]=tr[x0];++tr[x].cnt;
}

//被注释掉的Insert是错误写法,应该要等到指针指到了x节点才可以给x节点赋初值,不然x指针会跳到前面的版本上 

int Query(int l,int r,int a){
  int xl=rot[l-1],xr=rot[r],ans=0,t;
  for (int i=C;i>=0;--i){
    t=a>>i&1;
    if (tr[tr[xr].s[t^1]].cnt-tr[tr[xl].s[t^1]].cnt>0)
      ans|=1<<i,xl=tr[xl].s[t^1],xr=tr[xr].s[t^1];
    else xl=tr[xl].s[t],xr=tr[xr].s[t];
  }
  return ans;
}

int n,m,s[N*2+9];

Abigail into(){
  Build();
  Insert(0);
  scanf("%d%d",&n,&m);
  for (int i=1;i<=n;++i){
  	scanf("%d",&s[i]);
  	s[i]^=s[i-1];
  	Insert(s[i]);
  }
}

Abigail getans(){
  char opt;
  int l,r,x;
  for (int i=1;i<=m;++i){
  	opt=rc();
  	if (opt=='A'){
  	  scanf("%d",&x);
	  s[n+1]=s[n]^x;
	  Insert(s[++n]);
	}else{
	  scanf("%d%d%d",&l,&r,&x);
	  printf("%d\n",Query(l,r,s[n]^x));
  	}
  }
}

int main(){
  into();
  getans();
  return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值