1 条题解
-
0
自动搬运
来自洛谷,原作者为

一扶苏一
休息结束。邮箱 yifusuyi@qq.com搬运于
2025-08-24 22:22:12,当前版本为作者最后更新于2020-06-03 15:39:29,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
【0/1 Trie】【P6587】 超超的序列
Analysis
把下标看作一堆二进制串,建立一颗 01 Trie,在叶结点处维护以当前二进制串(以根节点到孩子的边为最低位,连接叶节点的边为最高位)的为下标的序列值,非叶节点维护子树和。不难发现对于一个在第 层(根为第 层),代表 的节点,其信息就是所有对 取模后值为 的下标对应的序列值之和。查询时直接查询子树和,修改时在 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
- 上传者