zoukankan      html  css  js  c++  java
  • bzoj3261 最大异或和

    Description

    给定一个非负整数序列 {a},初始长度为 N。
    有M个操作,有以下两种操作类型:
    1 、A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1。
    2 、Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:
    a[p] xor a[p+1] xor … xor a[N] xor x 最大,输出最大是多少。

    Input

    第一行包含两个整数 N  ,M,含义如问题描述所示。
    第二行包含 N个非负整数,表示初始的序列 A 。
    接下来 M行,每行描述一个操作,格式如题面所述。

    Output

    假设询问操作有 T个,则输出应该有 T行,每行一个整数表示询问的答案。

    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 。

    对于测试点 3-7,N,M<=80000 。
    对于测试点 8-10,N,M<=300000 。

    其中测试点 1, 3, 5, 7, 9保证没有修改操作。
    对于 100% 的数据, 0<=a[i]<=10^7。

    Sample Output

    4
    5
    6

    HINT

    对于100%的数据,0<=a[i]<=10^7

    正解:可持久化trie树。

    很高深的样子,其实就是可持久化线段树。。

    跟可持久化线段树一样的构造方法,最高位为根,两个儿子分别表示下一位的二进制是0和1。每次插入,就直接从第n个位置蒯过来。用b[i]表示a[1]-a[i]的异或和,b[i]在树上的一条链就加1。查询的时候,对于l和r,只要查询b[p-1]^b[n]^x的最大值就行。那么我们可以查询l-1到r-1的区间。如果当前位上的儿子存在与b[n]^x异或起来等于1的位,就跳到这个儿子上,否则跳到另一个儿子上,总之就是个贪心的思想吧,稍微想想就通了。然后这题空间真的太鬼了。。

     1 //It is made by wfj_2048~
     2 #include <algorithm>
     3 #include <iostream>
     4 #include <complex>
     5 #include <cstring>
     6 #include <cstdlib>
     7 #include <cstdio>
     8 #include <vector>
     9 #include <cmath>
    10 #include <queue>
    11 #include <stack>
    12 #include <map>
    13 #include <set>
    14 #define inf (1<<30)
    15 #define il inline
    16 #define RG register
    17 #define ll long long
    18 
    19 using namespace std;
    20 
    21 int ch[2][15000010],sum[15000010],rt[15000010],a[600010],n,m,sz;
    22 char s[5];
    23 
    24 il int gi(){
    25     RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    26     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
    27 }
    28 
    29 il void insert(RG int x,RG int &rt,RG int v){
    30     rt=++sz; RG int y=rt,t;
    31     for (RG int i=23;i>=0;--i){
    32     sum[y]=sum[x]+1,ch[0][y]=ch[0][x],ch[1][y]=ch[1][x];
    33     t=(v&(1<<i))>>i,ch[t][y]=++sz,x=ch[t][x],y=ch[t][y];
    34     }
    35     sum[y]=sum[x]+1; return;
    36 }
    37 
    38 il int query(RG int x,RG int y,RG int v){
    39     RG int res=0,t;
    40     for (RG int i=23;i>=0;--i){
    41     t=(v&(1<<i))>>i;
    42     if (sum[ch[t^1][y]]-sum[ch[t^1][x]]) res+=(1<<i),x=ch[t^1][x],y=ch[t^1][y];
    43     else x=ch[t][x],y=ch[t][y];
    44     }
    45     return res;
    46 }
    47 
    48 il void work(){
    49     n=gi()+1,m=gi(); RG int l,r,x; insert(rt[0],rt[1],0);
    50     for (RG int i=2;i<=n;++i) a[i]=gi()^a[i-1],insert(rt[i-1],rt[i],a[i]);
    51     for (RG int i=1;i<=m;++i){
    52     scanf("%s",s);
    53     if (s[0]=='A') n++,a[n]=gi()^a[n-1],insert(rt[n-1],rt[n],a[n]);
    54     else{ l=gi(),r=gi(),x=gi(); printf("%d
    ",query(rt[l-1],rt[r],x^a[n])); }
    55     }
    56     return;
    57 }
    58 
    59 int main(){
    60     work();
    61     return 0;
    62 }
  • 相关阅读:
    汇编写启动代码之关看门狗、设置栈、调用C、开关icache
    ARM汇编伪指令
    多寄存器访问、后缀、栈、!、^
    协处理器CP15操作指令
    常用的ARM指令
    汇编指令及其特点
    ARM的37个寄存器以及异常处理方法
    一步步点亮LED之汇编点亮LED
    机器学习_第一节_numpy
    函数进阶_生成器
  • 原文地址:https://www.cnblogs.com/wfj2048/p/6472363.html
Copyright © 2011-2022 走看看