1 条题解

  • 0
    @ 2025-8-24 22:22:13

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar 一扶苏一
    休息结束。邮箱 yifusuyi@qq.com

    搬运于2025-08-24 22:22:12,当前版本为作者最后更新于2020-06-03 15:39:29,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    【0/1 Trie】【P6587】 超超的序列

    Analysis

    把下标看作一堆二进制串,建立一颗 01 Trie,在叶结点处维护以当前二进制串(以根节点到孩子的边为最低位,连接叶节点的边为最高位)的为下标的序列值,非叶节点维护子树和。不难发现对于一个在第 mm 层(根为第 00 层),代表 xx 的节点,其信息就是所有对 2m2^m 取模后值为 xx 的下标对应的序列值之和。查询时直接查询子树和,修改时在 Trie 上打标记即可。

    啥,你说这和官方题解的 std 没啥区别?因为 01 Trie 和线段树本质上是相同的,显而易见这里把这个结构描述成 01 Trie 更加的自然。

    Code

    namespace Fusu {
    
    const int maxn = 2100005;
    
    int n, m;
    int a[maxn];
    
    struct Node {
      int sz;
      ll sum, tag;
      Node *trans[2];
    
      inline void maketag(const ll x) {
        sum += sz * x;
        tag += x;
      }
      inline void pushup() {
        sum = 0;
        for (auto u : trans) if (u) {
          sum += u->sum;
        }
      }
      inline void pushdown() {
        if (tag) {
          for (auto u : trans) if (u) u->maketag(tag);
          tag = 0;
        }
      }
    };
    Node Mem[maxn << 1], *pool = Mem;
    Node *New(const int p, const int d) {
      int t = 1 << d;
      auto x = pool++;
      if (d == 21) {
        if (p <= n) {
          x->sum = a[p];
          if (p != 0) x->sz = 1;
        }
        return x;
      }
      x->trans[0] = New(p, d + 1);
      x->trans[1] = New(p | t, d + 1);
      x->pushup();
      x->sz = x->trans[0]->sz + x->trans[1]->sz;
      return x;
    }
    
    Node *stk[maxn];
    int top = 0;
    void Main() {
      qr(n); qr(m);
      qra(a + 1, n);
      auto rot = New(0, 0);
      for (ll op, x, y, z, ans = 0; m; --m) {
        qr(op);
        op = (op + ans) % 2 + 1;
        qr(x); qr(y);
        y &= (1 << x) - 1;
        if (op == 1) {
          qr(z);
          auto u = rot;
          for (int i = 0, t = 1 << i; i < x; t = 1 << ++i) {
            stk[++top] = u;
            int k = (y & t) ? 1 : 0;
            u->pushdown();
            u = u->trans[k];
          }
          u->maketag(z);
          while (top) stk[top--]->pushup();
        } else {
          auto u = rot;
          for (int i = 0, t = 1 << i; i < x; t = 1 << ++i) {
            int k = (y & t) ? 1 : 0;
            u->pushdown();
            u = u->trans[k];
          }
          qw(ans = u->sum, '\n');
        }
      }
    }
    
    } // namespace Fusu
    
    • 1

    信息

    ID
    5564
    时间
    1000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者