CF242E XOR on Segment

CF242E XOR on Segment

codeforces
洛谷

关于异或,无法运用懒标记实现区间异或;

可以像trie树一样拆位,将每个值拆成二进制数,对此建相应个数的线段树。

0 1与 0异或 数字不变

0 1与 1异或 数字翻转

由此,对于一个01串的每一个字符都与1异或 则 1的个数 = 串长 - 现在1的个数

查询:对所有的线段树[l,r]查询1的个数,在乘上对应的二进制位权,他们之和就是查询的答案。

Code
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
const int M = 20;
int n, now;
vector<vector<int>> a;
class segtree {
public:
    struct node {
        int tag = 0;
        int64_t sum = 0;
        void apply(int l, int r) {
            // make v become node(tag,data) in modify
            sum = r - l + 1 - sum;
            tag ^= 1;
        }
        void init(int v) {
            // in build_tree init
            sum = v;
            tag = 0;
        }
    };

    node unite(const node &a, const node &b) const {
        node res;
        res.sum = a.sum + b.sum;
        return res;
    }
    // about x: left son is x+1 , right son is x+((mid-l+1)<<1) ;
    inline void push_down(int x, int l, int r) {
        int y = (l + r) >> 1;
        int z = x + ((y - l + 1) << 1);
        // push from x into (x + 1) and z
        if (tree[x].tag) {
            tree[x + 1].apply(l, y);
            tree[z].apply(y + 1, r);
            tree[x].tag = 0;
        }
    }

    int n;
    vector<node> tree;
    inline void push_up(int x, int z) { tree[x].sum = unite(tree[x + 1], tree[z]).sum; }
    void build(int x, int l, int r) {
        if (l == r) {
            tree[x].init(a[l][now]);
            return;
        }
        int y = (l + r) >> 1;
        int z = x + ((y - l + 1) << 1);
        build(x + 1, l, y);
        build(z, y + 1, r);
        push_up(x, z);
    }

    node get(int x, int l, int r, int ll, int rr) {
        if (ll <= l && r <= rr) {
            return tree[x];
        }
        int y = (l + r) >> 1;
        int z = x + ((y - l + 1) << 1);
        push_down(x, l, r);
        node res{};
        if (rr <= y)
            res = get(x + 1, l, y, ll, rr);
        else {
            if (ll > y)
                res = get(z, y + 1, r, ll, rr);
            else
                res = unite(get(x + 1, l, y, ll, rr), get(z, y + 1, r, ll, rr));
        }
        push_up(x, z);
        return res;
    }
    void modify(int x, int l, int r, int ll, int rr) {
        if (ll <= l && r <= rr) {
            tree[x].apply(l, r);
            return;
        }
        int y = (l + r) >> 1;
        int z = x + ((y - l + 1) << 1);
        push_down(x, l, r);
        if (ll <= y) modify(x + 1, l, y, ll, rr);
        if (rr > y) modify(z, y + 1, r, ll, rr);
        push_up(x, z);
    }

    segtree(int _n = ::n) : n(_n) {
        assert(n > 0);
        tree.resize(2 * n - 1);
    }

    node get(int ll, int rr) {
        assert(0 <= ll && ll <= rr && rr <= n - 1);
        return get(0, 0, n - 1, ll, rr);
    }

    void modify(int ll, int rr) {
        assert(0 <= ll && ll <= rr && rr <= n - 1);
        modify(0, 0, n - 1, ll, rr);
    }
};  // root's idx is 0 and the begin of vector is also 0;
// don't forget idx is from 0 to n-1 (equal [--x,--y]) when ask;
signed main() {
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(nullptr), std::cout.tie(nullptr);
    int q;
    cin >> n;
    segtree t[M];
    a.resize(n, vector<int>(M));
    for (int i = 0, x; i < n; ++i) {
        cin >> x;
        for (int j = 0; j < M; ++j) a[i][j] = x >> j & 1;
    }
    for (int i = 0; i < M; ++i) now = i, t[i].build(0, 0, n - 1);
    cin >> q;
    while (q--) {
        int op, l, r;
        cin >> op >> l >> r;
        --l, --r;
        if (op == 1) {
            int64_t ans = 0, p = 1;
            for (int i = 0; i < M; ++i, p <<= 1) ans += p * t[i].get(l, r).sum;
            cout << ans << endl;
        } else {
            int64_t k;
            cin >> k;
            for (int i = 0; i < M; ++i)
                if (k >> i & 1) t[i].modify(l, r);
        }
    }
    return 0;
}
posted @ 2022-07-30 00:53  Cattle_Horse  阅读(25)  评论(0编辑  收藏  举报