题解 P6587 【超超的序列 加强】
【0/1 Trie】【P6587】 超超的序列
Analysis
把下标看作一堆二进制串,建立一颗 01 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