P10856 【MX-X2-T5】「Cfz Round 4」Xor-Forces
P10856 【MX-X2-T5】「Cfz Round 4」Xor-Forces
给定长为 \(n=2^k\) 的数组 \(a_i\),下标从 \(0\) 开始,支持 \(q\) 次操作:
- 给定 \(x\),令 \(a_i \gets a_{i \oplus x}\)。
- 给定 \(l,r\),查询区间 \([l,r]\) 的颜色段数。
强制在线。
\(k \le 18\),\(q \le 2\times 10^5\),\(a_i \le n\),1 秒,512 MB。
将修改标记永久化,对全局打标记 \(x\) 表示下标偏移量,只要查询 \(a'_i=a_{i \oplus x}\) 的区间颜色段数。
区间颜色段是半群信息,记录端点处的颜色值可以 \(O(1)\) 合并,注意信息不具有交换律。
对原序列建线段树,预处理所有节点偏移 \(0 \sim \text{len}-1\) 的答案。将线段树视作 01-Trie 结构,合并时简单讨论即可。
断言 \(a_{l \oplus x}, a_{(l+1) \oplus x},\cdots a_{r \oplus x}\) 可以分解为静态线段树上 \(O(\log n)\) 个带偏移区间。
具体地,我们对 \([l,r]\) 进行递归分解,若 \(x\) 高位为 \(0\) 则直接递归,若 \(x\) 高位为 \(1\) 则需要交换左右子树。可以算出对应区间后递归,注意半群复合顺序是反过来的。静态线段树可以视作高位向低位的 01-Trie 结构。
复杂度 \(O(n \log n+q \log n)\)。
const int N = 3e5 + 5;
int c, n, k, q, a[N];
struct info {int vl, vr, cnt;};
const info I = {-1, -1, -1};
info operator+ (const info& a, const info& b) {
if (a.cnt == -1 || b.cnt == -1) return a.cnt != -1 ? a : b;
return info{a.vl, b.vr, a.cnt + b.cnt - (a.vr == b.vl)};
}
info& operator+= (info& a, const info& b) {return a = a + b;}
struct segtree {
#define ls (rt << 1)
#define rs (rt << 1 | 1)
info* val[4*N];
void build(int l = 0, int r = n-1, int rt = 1) {
int len = r-l+1;
val[rt] = new info[len];
if (l == r) return val[rt][0] = info{a[l], a[l], 1}, void();
int mid = (l + r) >> 1, h = len / 2;
build(l, mid, ls), build(mid + 1, r, rs);
for (int x = 0; x < len; x++) {
int x0 = x & (h - 1);
if (!(x & h)) val[rt][x] = val[ls][x0] + val[rs][x0];
else val[rt][x] = val[rs][x0] + val[ls][x0];
}
}
info ask(int tl, int tr, int x, int l = 0, int r = n-1, int rt = 1) {
if (tl <= l && r <= tr) return val[rt][x];
int mid = (l + r) >> 1, h = (r-l+1) / 2;
info res = I; int x0 = x & (h - 1);
if (tl <= mid) {
int ql = max(tl, l), qr = min(tr, mid);
if (!(x & h)) res += ask(ql, qr, x0, l, mid, ls);
else res += ask(ql+h, qr+h, x0, mid+1, r, rs);
}
if (tr > mid) {
int ql = max(tl, mid+1), qr = min(tr, r);
if (!(x & h)) res += ask(ql, qr, x0, mid+1, r, rs);
else res += ask(ql-h, qr-h, x0, l, mid, ls);
} return res;
}
} T;
void _main() {
cin >> c >> k >> q, n = 1 << k;
for (int i = 0; i < n; i++) cin >> a[i];
int x = 0; T.build();
#undef ls
for (int ls = 0, op, v, l, r; q--; ) {
cin >> op;
if (op == 1) {
cin >> v; x ^= c ? (v ^ ls) : v;
} else {
cin >> l >> r; c ? (l ^= ls, r ^= ls) : 0;
if (l > r) swap(l, r);
cout << (ls = T.ask(l, r, x).cnt) << '\n';
}
}
}

浙公网安备 33010602011771号