【BZOJ 3261】最大异或和【可持久化字典树】

题意

  给出一个长度为n的整数序列,给出m个操作。操作有两种。1,Ax表示在序列结尾增加x。2,Qlrx表示找到一个位置p满足 l<=p<=r,使得a[p] xor a[p+1]xor...xor a[n] xor x最大,并输出这个最大值。

分析

 今天学可持久化字典树的时候的找的一道模板题。对于这个题目其实只要学过主席树应该都能自己写出来(我照着主席树的套路写然后debug一下午然后发现num数组想错了mmp)

   我们定义sum[i]为a[1]xor a[2] xor ...xor a[i]。那么对于每个询问操作Qlrx,我们要找出一个[l,r]内的p使得sum[n]xor sum[p-1] xor x最大.而显然sum[n]xor x是一个常数,所以我们要找到一个p使得sum[p-1]xor某个常数最大。

   字典树的经典用法就是在一堆数字中,查询某个与x异或最大的是哪个数字。但是这个问题中有区间限制,所以我们需要将其可持久化。与线段树一样,我们记录每个历史版本,也就是前i个数字组成的字典树,根为root[i]。建树的思路和主席树几乎是完全一样的。只不过我们为了实现查询,多更新了一个num数组。因为主席树查询时候可以直接相减得到这个区间内各个数的数量,但是字典树不行,所以我们多维护一个num,来确定在[l,r]区间内,这个节点有没有走向0或者1的方法。

  

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 
 6 
 7 using namespace std;
 8 const int maxn=600000*24;
 9 int n,m,sz;
10 int ch[maxn][2],a[maxn],root[maxn],sum[maxn],val[maxn],num[maxn][2];
11 void update(int x,int y,int aa,int id){
12     root[x]=++sz;
13     x=root[x];
14     for(int i=23;i>=0;i--){
15         int c=(aa>>i)&1;
16         num[x][c]+=num[y][c]+1;
17         num[x][!c]=num[y][!c];
18         ch[x][!c]=ch[y][!c];
19         ch[x][c]=++sz;
20         memset(ch[sz],0,sizeof(ch[sz]));
21         x=ch[x][c],y=ch[y][c];
22     }
23     val[x]=id;
24 }
25 
26 int query(int x,int y,int aa){
27     for(int i=23;i>=0;i--){
28         int c=(aa>>i)&1;
29         if(num[x][!c]-num[y][!c])
30             x=ch[x][!c],y=ch[y][!c];
31         else
32             x=ch[x][c],y=ch[y][c];
33     }
34     return val[x];
35 }
36 
37 int main(){
38     scanf("%d%d",&n,&m);
39     sz=1;
40     sum[0]=0;
41     update(0,0,0,0);
42     for(int i=1;i<=n;i++){
43         scanf("%d",&a[i]);
44         sum[i]=sum[i-1]^a[i];
45         update(i,root[i-1],sum[i],i);
46     }
47     char c;
48     int l,r,x;
49     for(int i=1;i<=m;i++){
50         scanf(" %c",&c);
51         if(c=='A'){
52             n++;
53             scanf("%d",&a[n]);
54             sum[n]=sum[n-1]^a[n];
55             update(n,root[n-1],sum[n],n);
56         }else{
57             scanf("%d%d%d",&l,&r,&x);
58             printf("%d\n",sum[query(root[r-1],root[l-2],x^sum[n])]^sum[n]^x);
59         }
60     }
61 return 0;
62 }
63 //LQL
View Code

 

posted @ 2018-08-17 21:13  蒟蒻LQL  阅读(361)  评论(0编辑  收藏  举报