zoukankan      html  css  js  c++  java
  • P4735 最大异或和 /【模板】可持久化Trie

    //tire的可持久化
    //线段树的可持久化——主席树
    //可持久化的前提:本身的拓扑结构在操作时不变
    //可以存下来数据结构的所有历史版本
    //核心思想:只记录每一个版本与前一个版本不一样的地方 
    //
    
    //s[i]=a[1]^a[2]^a[3]^...^a[n]
    //a[p]^a[p+1]^...a[N]^x=s[p-1]^s[N]^x
    
    //对于s[N]^x
    //从最高位开始考虑
    //如果是1,那么就优先考虑是0的,如果有是0的,那么就把所有当前位为1的舍去,如果没有,再去考虑1的
    //如果是0,那么就优先考虑是1的,如果有是1的,那么就把所有当前位位0的社区,如果没有,再去考虑0的
    
    //假设左子树是当前位位0的 
    //询问左子树是否存在一个数的下标>=l
    //等价于左子树下标最大值是否>=l
    //所以可以记录一个max_id,表示当前子树中,下标最大值 
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    const int N = 600010, M = N * 25;
    int n, m;
    int s[N];
    //01串,所以开2     记录最大的id  
    int tr[M][2], max_id[M];
    //记录根节点     
    int root[N], idx;
    //i:当前第几位,前缀和s的下标 
    //k:当前处理到第几位
    //p:上一个版本
    //q:最新版本 
    void insert(int i, int k, int p, int q)
    {
        //说明处理完最后一位 
        if (k < 0)
        {
            //存的是叶节点,叶节点的max_id就是本身 
            max_id[q] = i;
            return;
        }
        //当前这一位 
        int v = s[i] >> k & 1;
        //如果p存在,就表示之前已经插入的数字中,存在数字这一位存在1  
        if (p)
            //要把其他的信息复制过来,当前儿子不用复制过来,其他的要复制过来 
            tr[q][v ^ 1] = tr[p][v ^ 1]; 
        //当前这一位开新的点 , 
        tr[q][v] = ++ idx;
        //进行下一位 
        insert(i, k - 1, tr[p][v], tr[q][v]);
        //更新最大id 
        max_id[q] = max(max_id[tr[q][0]], max_id[tr[q][1]]);
    }
    //            根        当前值        左边界限制 
    int query(int root, int C, int L)
    {
        //从根节点开始 
        int p = root;
        //每一位 
        for (int i = 23; i >= 0; i -- )
        {
            int v = C >> i & 1;
            //判断对立面是否存在 
            if (max_id[tr[p][v ^ 1]] >= L) 
                p = tr[p][v ^ 1];
            else 
                p = tr[p][v];
        }
        return C ^ s[max_id[p]];
    }
    int main()
    {
        scanf("%d%d", &n, &m);
        //根节点  带前缀和之后坐标从0开始
        //初始化为-1 
        max_id[0] = -1;
        //插入x[0]的这个版本 
        root[0] = ++ idx;
        //        从第23位开始,最一开始上个版本没有,所以为0
        //                当前版本为root[0] 
        insert(0, 23, 0, root[0]);
        for (int i = 1; i <= n; i ++ )
        {
            int x;
            scanf("%d", &x);
            //前缀和 
            s[i] = s[i - 1] ^ x;
            //赋根节点 
            root[i] = ++ idx;
            //当前是第i位,从23位开始,前一个根节点,当前根节点 
            insert(i, 23, root[i - 1], root[i]);
        }
        char op[2];
        int l, r, x;
        //操作 
        while (m -- )
        {
            scanf("%s", op);
            //插入 
            if (*op == 'A')
            {
                scanf("%d", &x);
                n ++ ;
                //前缀和 
                s[n] = s[n - 1] ^ x;
                //新版本根节点 
                root[n] = ++ idx;
                //插入 
                insert(n, 23, root[n - 1], root[n]);
            }
            else
            {
                scanf("%d%d%d", &l, &r, &x);
                //要找p-1
                //所以区间是l-1到r-1 
                //限制是l-1 
                printf("%d
    ", query(root[r - 1], s[n] ^ x, l - 1));
            }
        }
        return 0;
    }
  • 相关阅读:
    模板模式创建一个poi导出功能
    vim python和golang开发环境配置
    vim快捷键
    golang聊天室
    goroutine与channels
    Redis中的GETBIT和SETBIT(转载)
    二叉树
    满二叉树与完全二叉树
    拓扑排序
    ZigZag Conversion
  • 原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12308424.html
Copyright © 2011-2022 走看看