zoukankan      html  css  js  c++  java
  • [P4735] 最大异或和——可持久化trie + 思维

    给定n个数字,m个操作

    操作1是往数组最后添加一个数字x

    操作2是给出[L, R],与数字x,输出在[L, R]中选一个数字p使得,a[p]^a[p+1]^...^a[n]^x的值最大

    首先,考虑题目要求的是【1,R】的话,那么其实这道题无非就是可持久化trie + 前缀和异或而已。

    但是问题就是有一个L。那么该如何处理这个L呢。我们考虑trie树的每一个节点多维护一个信息(以前没想过trie树每个节点还能带别的信息,这次学到了!

    即经过的最大前缀和编号,那么我们在query的时候就只需要check一下当前点的最大前缀和编号是否小于L即可。(y总讲得真好

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 6e5+10;
    const int M = N*25;
    
    int tr[M][2];
    int root[N], sum[N];
    int max_id[M];
    int id;
    
    void _insert(int k, int pre, int now) {
        max_id[now] = k;
        for (int i = 24; i >= 0; i --) {
            int v = sum[k] >> i & 1;
            if (pre) tr[now][v^1] = tr[pre][v^1];
            tr[now][v] = ++id;
            max_id[ tr[now][v] ] = k;
            now =  tr[now][v] ;
            pre =  tr[pre][v] ;
        }
    }
    
    int query(int val, int L, int now) {
        for (int i = 24; i >= 0; i --) {
            int v = val >> i & 1;
            if (max_id[tr[now][v^1]] >= L) now = tr[now][v^1]; //check一下当前点的最大前缀和编号是否小于L
            else now = tr[now][v];
        }
        return val ^ sum[max_id[now]];
    }
    
    int main() {
        int n, m; scanf("%d%d", &n, &m);
        
        root[0] = ++id;
        max_id[0] = -1; ///这里需要置成比0小的数,因为0这个编号其实是存在的(sum[0]),所以我们不能赋值为0
        _insert(0, 0, root[0]); ///这里需要插入0这个值的,因为这个是前缀和异或,那么就有sum[n] ^ 0的情况出现。
    
        int l, r, x;
        for (int i = 1; i <= n; ++ i) {
            scanf("%d", &x);
            root[i] = ++id;
            sum[i] = sum[i-1] ^ x;
            _insert(i, root[i-1], root[i]);
        }
        char op[2];
        while (m--) {
            scanf("%s", op);
            if (op[0] == 'A') {
                scanf("%d", &x);
                ++ n;
                root[n] = ++id;
                sum[n] = sum[n-1] ^ x;
                _insert(n, root[n-1], root[n]);
            }
            else {
                scanf("%d%d%d", &l, &r, &x);
                int ans = query(sum[n]^x, l-1, root[r-1]);
                printf("%d
    ", ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    Hibernate 查询,返回结果设置到DTO
    sqlserver计算时间差DATEDIFF 函数
    SQL语句 不足位数补0
    Redis详细用法
    windows下安装Redis并部署成服务
    Redis命令
    ajax请求在参数中添加时间戳
    JS获取子节点、父节点和兄弟节点的方法实例总结
    js关闭当前页面清除session
    Java面试题一览
  • 原文地址:https://www.cnblogs.com/Vikyanite/p/15154715.html
Copyright © 2011-2022 走看看