voidsplit(int u, int &x, int &y, int l, int r, int bit) { x = y = 0; if (!u || !tr[u].sz) return; if (bit < 0 || (l == 0 && r == 2 * (1 << bit) - 1)) { x = u; return; } int mid = 1 << bit; // std::cout << u << ' ' << l << ' ' << r << ' ' << bit << ' ' << tr[u].sz << '\n'; pushdown(u, bit); if (l >= mid) y = u, split(tr[u].s[1], tr[x = ++ tot].s[1], tr[u].s[1], l ^ mid, r ^ mid, bit - 1); elseif (r < mid) y = u, split(tr[u].s[0], tr[x = ++ tot].s[0], tr[u].s[0], l, r, bit - 1); else { // if (l == 0 && r == mid * 2 - 1) return x = u, void(); x = u, y = ++ tot; split(tr[u].s[0], tr[u].s[0], tr[y].s[0], l, mid - 1, bit - 1); split(tr[u].s[1], tr[u].s[1], tr[y].s[1], 0, r ^ mid, bit - 1); } pushup(x), pushup(y); }
合并两棵子树
没什么好讲的,注意到了叶子节点只能保留一个信息即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
intmerge(int x, int y, int bit) { // std::cout << "MERGE " << x << ' ' << y << ' ' << bit << '\n'; if (!x || !tr[x].sz) return y; if (!y || !tr[y].sz) return x; if (bit < 0) { // std::cout << tr[x].val << ' ' << tr[y].val << std::endl; assert(!tr[x].sz || !tr[y].sz || tr[x].val == tr[y].val); return tr[x].sz ? x : y; } pushdown(x, bit), pushdown(y, bit); tr[x].s[0] = merge(tr[x].s[0], tr[y].s[0], bit - 1); tr[x].s[1] = merge(tr[x].s[1], tr[y].s[1], bit - 1); returnpushup(x), x; }
voidallxor(int x, int bit, int lt){ if (!x) return; int v = tr[x].val, lv = tr[x].lval; if (lt >> bit & 1) std::swap(tr[x].s[0], tr[x].s[1]); tr[x].val = (v ^ lt) | (v & lv & lt); tr[x].lval = (lv ^ lt) | (v & lv & lt); tr[x].lt ^= lt; }
voidpushdown(int x, int bit) { if (!x || !tr[x].lt || !tr[x].sz) return; allxor(tr[x].s[0], bit - 1, tr[x].lt), allxor(tr[x].s[1], bit - 1, tr[x].lt); tr[x].lt = 0; }
voidallor(int u, int bit, int val) { if (!u || !tr[u].sz) return; int add = val & tr[u].lval; if (!(add & tr[u].val)) returnallxor(u, bit, add); pushdown(u, bit); int mid = 1 << bit; if (val & mid) allxor(tr[u].s[0], bit - 1, mid), tr[u].s[1] = merge(tr[u].s[0], tr[u].s[1], bit - 1), tr[u].s[0] = 0; allor(tr[u].s[0], bit - 1, val), allor(tr[u].s[1], bit - 1, val); pushup(u); }
对全局 and
容易发现 $v\odot x = \neg(\neg v |x)$,那么就可以拆分成 or 和 xor 操作。这个就好做了。