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

    Description

    给定一个长度为 (n) 的序列 (A),有 (m) 次操作,每次要么在序列尾部再添加一个数,将序列长度 (n) 加一,要么给进行一次查询,给定查询参数 (l,~r,~x) 要求在 ([l,~r]) 内找一个位置 (p),要求最大化 (x~~xor ~~Xor_{i = p}^{n} A_i)

    Limitation

    (1 leq n,~m leq 3 imes 10^5)

    (0 leq A_i leq 10^7)

    Solution

    考虑由于带加入,后缀异或和不太好维护,于是考虑维护前缀异或和 ({presum}),那么每次询问等于找一个点 (p in [l - 1, r)),最大化 (presum_p~~xor~~presum_n~~xor~~x)

    由于 (presum_n~~xor~~x) 是已知的,于是问题就是查询区间内一个位置最大化该点和某个给定值的异或值。 考虑类似主席树的建树方法建立可持久化0/1Trie,在 Trie 的每个节点记录前缀该节点共有几个为 (0) 的孩子和为 (1) 的孩子,相减即可维护对应区间每个节点是否有对应孩子。

    有几个需要注意的细节,首先是由于查的是前缀-1,所以允许如果 $l =1 $ 则前缀什么都不选,因此 (presum_0) 应插入一个 (0) 而不是置为空。另外注意通过查询的位置 (x)(p - 1),对应相减的可持久化0/1Tire所维护的版本号应是 (l - 2,~r - 1)。当 (l = 1) 时需要特判维护版本号是 (l - 1, r - 1),同时如果 (r = 1) 则对应查询的版本号为 (0,~0),当然什么也查不到,应该特判这种情况。另外由于插入 (m) 个数,原始 (n) 个数,所以数组需要开 (n + m)

    Code

    卡常的题都是屑题

    出卡常题的出题人都是毒瘤出题人

    好吧被卡的很难受,做了一点优化。

    首先是注意到无论是插入还是查询,在0/1Trie上走的路径都是一条链而不具备分叉结构,所以不需要递归只需要循环即可解决问题。但是貌似意义不大,因为递归了写的也是尾递归,貌似开了 -O2 以后会被自动优化成循环233333所以并不能解决问题

    写了个内存池,这个玩意真tm有用……甩动态分配内存两条街……

    然后就最慢 (940s) 卡着过了

    #include <cstdio>
    #include <algorithm>
    
    const int maxn = 600005;
    const int upceil = 25;
    const int tupceil = 24;
    const int maxt = maxn * upceil;
    
    struct Tree {
      Tree *ch[2];
      int v[2];
    
      Tree() { ch[0] = ch[1] = NULL; v[0] = v[1] = 0; }
    };
    Tree *rot[maxn], *pool[maxt], qwq[maxt];
    
    int n, m, sum, top;
    int MU[maxn];
    
    void build(Tree *u, Tree *pre, const int v, int p);
    int query(const Tree *const pre, const Tree *const u, const int v, const int p);
    
    int main() {
      freopen("1.in", "r", stdin);
      qr(n); qr(m);
      for (int i = 0; i < maxt; ++i) pool[i] = qwq + i;
      build(rot[0] = pool[top++], NULL, 0, tupceil);
      for (int i = 1, x; i <= n; ++i) {
        x = 0; qr(x);
        build(rot[i] = pool[top++], rot[i - 1], sum ^= x, tupceil);
      }
      for (int a, b, c; m; --m) {
        a = 0;
        do a = IPT::GetChar(); while ((a != 'A') && (a != 'Q'));
        if (a == 'A') {
          a = 0; qr(a);
          build(rot[n + 1] = pool[top++], rot[n], sum ^= a, tupceil);
          ++n;
        } else {
          a = b = c = 0; qr(a); qr(b); qr(c);
          if (b == 1) {
            qw(sum ^ c, '
    ', true);
            continue;
          }
          qw(query(rot[std::max(0, a - 2)], rot[b - 1], sum ^ c, tupceil) ^ sum ^ c, '
    ', true);
        }
      }
      return 0;
    }
    
    void build(Tree *u, Tree *pre, const int v, int p) {
      while (~p) {
        if (pre) *u = *pre;
        int x = (v & (1 << p)) >> p;
        ++u->v[x];
        u = u->ch[x] = pool[top++];
        if (pre) pre = pre->ch[x];
        --p;
      }
    }
    
    int query(const Tree *pre, const Tree *u, const int v, int p) {
      int _ret = 0;
      while (~p) {
        int x = ((v & (1 << p)) >> p) ^ 1, y = u->v[x] - (pre ? pre->v[x] : 0);
        if (!y) x ^= 1;
        _ret |= (x << p);
        u = u->ch[x];
        if (pre) pre = pre->ch[x];
        --p;
      }
      return _ret;
    }
    
  • 相关阅读:
    进程之管道Pipe,数据共享Manager,进程池Poo
    进程之锁,信息量,事件,队列,生产者消费者模型,joinablequeue
    网络编程之sock server,自定义一个与sock server类相似的功能,支持多客户端通信
    网络编程之粘包解决方案
    进程之进程创建的两种方式,两种传值的方式,验证进程间数据隔离,join,守护进程,僵尸进程,孤儿进程
    毕业设计开题报告任务书参考文献格式和数量要求
    剑指offer-替换空格
    剑指offer-二维数组中的查找
    用forward和sendRedirect转发时的区别
    ServletContext实现显示用户在线人数
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/11196800.html
Copyright © 2011-2022 走看看