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

    BZOJ3261: 最大异或和

    Description

    给定一个非负整数序列{a},初始长度为N。
    有M个操作,有以下两种操作类型:
    1、Ax:添加操作,表示在序列末尾添加一个数x,序列的长度N+1。
    2、Qlrx:询问操作,你需要找到一个位置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保证没有修改操作。
    0<=a[i]<=10^7。

    Sample Output

    4
    5
    6

    题解Here!
    本来以为是一道线段树题。。。
    但是这个异或不怎么好维护。
    看完题解发现是一道可持久化$Trie$树。。。
    蒟蒻表示啥都不知道。。。

    可持久化字典树就是记录在字典树上有相同前缀的前缀和(节点的个数)。

    然后通过取差值(右边界减去左边界)判断一段区间内是否有字典树上的前缀。

    做法就是对于每一个节点新建一颗字典树,记录下节点对应的字典树根的位置。

    在插入过程中,对于插入的数的所有前缀都新建一个节点。

    此节点拥有字典树上相同前缀的前缀和就是他父亲(此题是序列中的前一个数)的前缀和加一。

    其他的前缀全部指向父亲的对应节点,因为前缀和没有改变。

    然后此题

    询问区间中一个点到$n$的异或和与$x$异或最大,也就是$n$的异或前缀与$x$异或后的值与区间内任意前缀亦或最大。

    所以将$n$的异或前缀与$x$异或的值丢进字典树中贪心查找最大异或就可以了。

    具体看代码吧,本蒟蒻也是第一次写这玩意,码风还没有成型。。。

    附带码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #define MAXN 600010
    using namespace std;
    int n,m,size=0,sum=0;
    int val[MAXN],root[MAXN];
    struct Persistable_Trie{
        int val,son[2];
    }a[MAXN<<5];
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    void insert(int v,int rt,int f){
        root[rt]=++size;
        rt=root[rt];f=root[f];
        for(int i=28;i>=0;i--){
            int t=(v>>i)&1;
            if(!a[rt].son[t]){
                a[rt].son[t]=++size;
                a[rt].son[t^1]=a[f].son[t^1];
                a[a[rt].son[t]].val=a[a[f].son[t]].val;
            }
            rt=a[rt].son[t];
            f=a[f].son[t];
            a[rt].val++;
        }
    }
    int query(int l,int r,int v){
        int ans=0,s=val[l]^v;
        l=root[l];r=root[r];
        for(int i=28;i>=0;i--){
            int t=(v>>i)&1;
            if(a[a[r].son[t^1]].val>a[a[l].son[t^1]].val){
                ans+=1<<i;
                t^=1;
            }
            l=a[l].son[t];
            r=a[r].son[t];
        }
        return max(ans,s);
    }
    void work(){
        char ch[2];
        int x,y,k;
        while(m--){
            scanf("%s",ch);x=read();
            if(ch[0]=='A'){
                val[++n]=sum^=x;
                insert(sum,n,n-1);
            }
            else{
                y=read();k=read();
                printf("%d
    ",query(x-1,y-1,sum^k));
            }
        }
    }
    void init(){
        n=read();m=read();
        for(int i=1;i<=n;i++){
            val[i]=sum^=read();
            insert(sum,i,i-1);
        }
    }
    int main(){
        init();
        work();
        return 0;
    }
    
  • 相关阅读:
    ModelForm详解
    form中choice从数据库实时更新
    django-form字段和插件widgets速查
    Form生成的label标签详解
    form+ajax实现验证
    微分方程的解
    easyui中连接按钮样式
    easyui中设置开始日期只能选择比结束日期小的日期,js代码获取日期的值
    三目表达式问题
    easyui中在formatter: function (value, row,index) {中添加删除方法
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9465562.html
Copyright © 2011-2022 走看看