zoukankan      html  css  js  c++  java
  • [BZOJ3261]最大异或和

    题目大意:

    给定一个非负整数序列{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 最大,输出最大是多少。

    解题思路:

    首先,a[1] xor a[2] xor ... xor a[N] xor x很容易求出。

    然后,异或满足交换律和结合律。

    此处询问的是后缀,我们考虑转化成前缀异或。

    设s[i]表示a[1] xor a[2] xor ... xor a[i]

    即在([l-1,r-1])中找一个数p,使s[N] xor x xor s[p]最大。

    用可持久化Trie维护前缀异或信息,和节点个数,然后在区间内进行前缀差查询(可持久化Trie满足可加性),每次贪心地使高位尽可能大即可。

    于是长得和主席树差不多。

    毒瘤数据结构大法好o((⊙﹏⊙))o

    C++ Code:

    #include<bits/stdc++.h>
    int n,m,s[600006],b[25],cnt=0,ans,rt[600006];
    struct node{
        int ch[2],c;
    }d[22000006];
    void add(int&o,int&pr,int nw){
        o=++cnt;
        if(!~nw){d[o].c=d[pr].c+1;return;}
        d[o].ch[0]=d[pr].ch[0];
        d[o].ch[1]=d[pr].ch[1];
        add(d[o].ch[b[nw]],d[pr].ch[b[nw]],nw-1);
        d[o].c=d[d[o].ch[0]].c+d[d[o].ch[1]].c;
    }
    void ask(int&R,int&L,int nw){
        if(!~nw)return;
        int _1=b[nw]^1;
        if(d[d[R].ch[_1]].c>d[d[L].ch[_1]].c){
            ans|=1<<nw;
            ask(d[R].ch[_1],d[L].ch[_1],nw-1);
        }else
        ask(d[R].ch[b[nw]],d[L].ch[b[nw]],nw-1);
    }
    inline int readint(){
        int c=getchar(),d=0;
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar())
        d=(d<<3)+(d<<1)+(c^'0');
        return d;
    }
    int main(){
        n=readint(),m=readint();
        s[0]=0;
        for(int i=1;i<=n;++i){
            int q=readint();
            s[i]=s[i-1]^q;
            for(int j=24;~j;--j)
            b[j]=(s[i]>>j)&1;
            add(rt[i],rt[i-1],24);
        }
        while(m--){
            char c[2];
            scanf("%s",c);
            if(c[0]=='A'){
                int q=readint();
                ++n;
                s[n]=s[n-1]^q;
                for(int j=24;~j;--j)
                b[j]=(s[n]>>j)&1;
                add(rt[n],rt[n-1],24);
            }else{
                ans=0;
                int l=readint(),r=readint(),x=readint(),p;
                p=s[n]^x;
                if(r==1){
                    printf("%d
    ",p);
                    continue;
                }
                for(int j=24;~j;--j)
                b[j]=(p>>j)&1;
                ask(rt[r-1],l-2>0?rt[l-2]:rt[0],24);
                printf("%d
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    [linux]Linux下的log
    [WDT]内部看门狗和外部看门狗
    [misc]printf/fprintf/sprintf/snprintf函数
    [Linux]read/write和fread/fwrite有什么区别
    移动端图片操作(二)——预览、旋转、合成
    移动端图片操作(一)——上传
    实现tap的多种方式
    Hammer.js分析(四)——recognizer.js
    Hammer.js分析(三)——input.js
    Hammer.js分析(二)——manager.js
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/9385594.html
Copyright © 2011-2022 走看看