zoukankan      html  css  js  c++  java
  • bzoj 3261: 最大异或和 (可持久化trie树)

    3261: 最大异或和

    Time Limit: 10 Sec  Memory Limit: 512 MB

    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  。

    令b[i]=a[1]^a[2]^a[3]^……^a[i]

    a[l]^a[l+1]^a[l+2] ……^a[r]=b[l-1]^b[r]

    所以ans=max(b[p-1]^b[n]^x) l<=p<=r

    所以要查询就是 在区间[l-1,r-1]内找max(b[i]^b[n]^x)

    结合主席树查询前缀和相减,所以操作区间为[l-2,r-1]

    所以,要将所有节点整体后移一位

    所以可持久化trie树中实际操作区间为[l-1,r]

    注意:整体后移后,root[1]处应添加全为0的节点

    例: 初始2个点 5  1

    询问 1 1 9,ans=5^1^9=13

    可持久化trie树操作区间:[0,1]

    若果root[1]处没有添加全为0的节点,sum怎么减都是0

    (描述不是很清楚,具体看代码中query函数)

    #include<cstdio>
    using namespace std;
    int n,m,tot;
    int root[600001],ch[600001*25][2];
    int b[600001],sum[600001*25];
    struct TRIE
    {
        void insert(int pre,int & now,int d,int w)
        {
            if(!now) now=++tot;
            sum[now]=sum[pre]+1;
            if(d<0) return;
            int p=1&(w>>d);
            ch[now][p^1]=ch[pre][p^1];
            insert(ch[pre][p],ch[now][p],d-1,w);
        }
        int query(int l,int r,int d,int w)
        {
            if(d<0) return 0;
            int p=1&(w>>d);
            if(sum[ch[r][p^1]]-sum[ch[l][p^1]]) return (1<<d)+query(ch[l][p^1],ch[r][p^1],d-1,w);
            else return query(ch[l][p],ch[r][p],d-1,w);
        }
    }Trie;
    int main()
    {
        scanf("%d%d",&n,&m); 
        int x,K=25;  n++;
        Trie.insert(root[0],root[1],K,0);
        for(int i=2;i<=n;i++)
        {    
              scanf("%d",&x);
            b[i]=b[i-1]^x;
            Trie.insert(root[i-1],root[i],K,b[i]); 
        }
        char c[3]; int l,r; 
        while(m--)
        {
            scanf("%s",c);
            if(c[0]=='A') 
            {
                scanf("%d",&x); n++;
                b[n]=b[n-1]^x;
                Trie.insert(root[n-1],root[n],K,b[n]);
            }
            else
            {
                scanf("%d%d%d",&l,&r,&x);
                x^=b[n];
                printf("%d
    ",Trie.query(root[l-1],root[r],K,x));
            }
        }
    }
  • 相关阅读:
    js调试技巧
    Java编程技巧——构建器
    java设计模式:工厂方法模式(Factory Method)
    23种设计模式导航
    java设计模式:单例模式(Singleton Pattern)
    迭代器与生成器
    装饰器
    文件操作的说明与使用
    函数命名、调用小技巧
    各类型数据的操作方法
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/6863508.html
Copyright © 2011-2022 走看看