zoukankan      html  css  js  c++  java
  • 【题解】洛谷P4735最大异或和

      学习了一下可持久化trie的有关姿势~其实还挺好理解的,代码也短小精悍。重点在于查询某个历史版本的trie树上的某条边是否存在,同样我们转化到维护前缀和来实现。同可持久化线段树一样,我们为了节省空间继承上一节点未修改的信息,修改的信息我们则新建一条链。节点上我们维护从最初的版本到当前版本这条路径一共出现了多少次,如果查询的最后版本记录这条路径出现的次数 > 查询的第一个版本的上一个版本的这条路径出现的次数,则说明这条路径存在在我们查询的范围内。

      对于这道题来说,不大好处理的是查询是一段后缀,而后缀是实时修改的。我们考虑将后缀转化为前缀 :(x wedge (a[p] wedge a[p + 1] ... wedge a[n]) = x wedge (a[1] wedge a[2] ... wedge a[n] ) wedge (a[1] wedge a[2] wedge ... wedge a[p - 1]))。如果将后一个式子转化为前缀异或的形式的话,我们有原式等于 (x wedge s[n] wedge s[p - 1])。(x wedge s[n]) 是一个定值,所以我们只需要求出一段前缀与这个定值的异或和即可。所以我们可以利用可持久化trie树,查询对应范围内的值贪心获得答案。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 600100
    int n, m, tot, root[maxn];
    int cnt[maxn * 28], ch[maxn * 28][2];
    int s[maxn];
    
    int read()
    {
        int x = 0, k = 1;
        char c; c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void insert(int now, int pre, int t, int x)
    {
        if(t < 0) return;
        int i = (x >> t) & 1;
        ch[now][!i] = ch[pre][!i];
        ch[now][i] = ++ tot;
        cnt[ch[now][i]] = cnt[ch[pre][i]] + 1;
        insert(ch[now][i], ch[pre][i], t - 1, x);
    }
    
    int Query(int now, int ath, int t, int x)
    {
        if(t < 0) return 0;
        int y = (x >> t) & 1;
        if(cnt[ch[ath][!y]] > cnt[ch[now][!y]])
            return (1 << t) + Query(ch[now][!y], ch[ath][!y], t - 1, x);
        else return Query(ch[now][y], ch[ath][y], t - 1, x);
    }
    
    int main()
    {
        n = read(), m = read();
        root[0] = ++ tot; insert(root[0], 0, 25, 0);
        for(int i = 1; i <= n; i ++) 
        {
            int x = read();
            s[i] = s[i - 1] ^ x; root[i] = ++ tot;
            insert(root[i], root[i - 1], 25, s[i]);
        }
        for(int i = 1; i <= m; i ++)
        {
            scanf("%s", s);
            if(s[0] == 'A')
            {
                int x = read(); ++ n; s[n] = s[n - 1] ^ x;
                root[n] = ++ tot; insert(root[n], root[n - 1], 25, s[n]);
            }
            else 
            {
                int l = read(), r = read(), x = read();
                l --, r --;
                if(l == 0) printf("%d
    ", Query(0, root[r], 25, x ^ s[n]));
                else printf("%d
    ", Query(root[l - 1], root[r], 25, x ^ s[n]));
            }
        }
        return 0;
    }
  • 相关阅读:
    补充缺失日期及对应数据
    通过拆分字段优化SQL
    left join 改写标量子查询
    对数据按组排序
    注册通用验证用户filter
    asp.net mvc FormsAuthentication一些问题
    il code swtich
    C# Equals
    Linq源代码阅读
    dotnet il editor 调试 iis 程序
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9781014.html
Copyright © 2011-2022 走看看