zoukankan      html  css  js  c++  java
  • BZOJ3261 最大异或和 解题报告(可持久化Trie树)

    本题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3261

    题目描述

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

    输入

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

    输出

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

    样例输入

    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。

    样例输出

    4
    5
    6
     

    题解:

    在这道题目之前,我想读者需要一个前置知识便于理解。请看我的另一篇博客:https://www.cnblogs.com/xxzh/p/9178838.html
    如果学会了这个知识的话,也就是知道了如何使用一颗01 Trie树
    那么考虑这道题,很显然,现在我们需要维护一颗可持久化trie树。如果不清楚静态主席树原理的,请移步我的另一篇博客:https://www.cnblogs.com/xxzh/p/9158819.html
     
    正式开始对这题讲解:
    对于每次操作Q,它给的算式太鬼了,实际上应该化成max( (a[n] xor x)xor a[p-1] ) p∈[l,r];
     
    对每个前置建立Trie,建立原理参考主席树博客。
    在建树的过程中,很重要的一点就是我们每次插入的节点其实是原来a数组中的前缀。也就是说我们维护的是前缀和的前缀(有点绕读者仔细琢磨)
     
    然后注意看算式,我们每次找的其实是p-1,注意是p-1而不是p。
    也就是本来我们query查找的应该是l-1到r,由于是p-1我们现在查找的是l-2到r-1
    当然,对于处理p-1我们也有方法,只需要在原来的数组a之前加一个0,这样的话就可以直接算l-1到r了
     
    具体的操作还是贪心的从高位到低位建立Trie,查询的时候注意减一下
    下面附上代码:
    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=6e5+15;
    int n,m,sz;
    int t[maxn<<5][2],sum[maxn<<5],b[maxn],q[maxn];
    inline int read(){
        char ch=getchar();
        int s=0,f=1;
        while (!(ch>='0'&&ch<='9')) {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    int ins(int last,int val)
    {
        int res,k;
        res=k=++sz;
        for (int i=23;i>=0;i--)
        {
            sum[k]=sum[last]+1;
            t[k][0]=t[last][0];t[k][1]=t[last][1];
            bool d=val&(1<<i);
            k=t[k][d]=++sz;last=t[last][d];
        }
        sum[k]=sum[last]+1;
        return res;
    }
    int query(int k1,int k2,int val)
    {
        int res=0;
        for (int i=23;i>=0;i--)
        {
            bool d=val&(1<<i);
            if (sum[t[k2][d^1]]-sum[t[k1][d^1]]>0){
                res|=(1<<i);
                k1=t[k1][d^1];
                k2=t[k2][d^1];
            }
            else k1=t[k1][d],k2=t[k2][d];
        }
        return res;
    }
    int main()
    {
        n=read()+1;m=read();
        q[1]=ins(q[0],b[1]);
        for (int i=2;i<=n;i++)
        {
            b[i]=b[i-1]^read();//注意插入trie的是前缀和 
            q[i]=ins(q[i-1],b[i]);
        }
        for (int i=1;i<=m;i++)
        {
            char ch=getchar();
            while (!(ch=='A'||ch=='Q')) ch=getchar();
            if (ch=='A') {
                ++n;
                b[n]=b[n-1]^read();
                q[n]=ins(q[n-1],b[n]);
            }
            else {
                int l=read(),r=read(),x=read();
                printf("%d
    ",query(q[l-1],q[r],x^b[n]));
            }
        }
        return 0;
    }
  • 相关阅读:
    智能移动机器人背后蕴含的技术——激光雷达
    Kalman Filters
    Fiddler抓HttpClient的包
    VSCode开发WebApi EFCore的坑
    WPF之小米Logo超圆角的实现
    windows react打包发布
    jenkins in docker踩坑汇总
    Using ML.NET in Jupyter notebooks 在jupyter notebook中使用ML.NET ——No design time or full build available
    【Linux知识点】CentOS7 更换阿里云源
    【Golang 报错】exec gcc executable file not found in %PATH%
  • 原文地址:https://www.cnblogs.com/xxzh/p/9188295.html
Copyright © 2011-2022 走看看