首页 > 其他 > 详细

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

时间:2018-08-17 22:08:06      阅读:143      评论:0      收藏:0      [点我收藏+]

题意

  给出一个长度为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

 

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

原文:https://www.cnblogs.com/LQLlulu/p/9495318.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!