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';
        }
    } 
} 
posted @ 2026-10-06 17:35  stripe_python  阅读(2)  评论(0)    收藏  举报