洛谷P6225 [eJOI 2019] 异或橙子

26 阅读2分钟

www.luogu.com.cn/problem/P62…

这道题第一眼看以为要把所有数拆成32位...然后每一位构建一个树状数组来操作...把自己搞得很晕。后来发现根本就不用这么麻烦,直接分析异或的性质即可。

首先对于异或,我们有 xx=0x\oplus x=0 ,以及 x0=xx\oplus 0=x .

我们考虑一个询问的区间 [l,r][l,r] ,设 p[l,r]p\in [l,r] ,则显然以 pp 为结尾的区间共有 pl+1p-l+1 个;以 pp 为开头的区间共有 rp+1r-p+1 个,则所有包含 pp 的区间共有 (pl+1)(rp+1)(p-l+1)(r-p+1) 个。

llrr 的奇偶性不同,对于任意一个位置 pp ,它均会在答案里贡献偶数次,则 apapap...ap=0a_p\oplus a_p\oplus a_p\oplus ... \oplus a_p=0

llrr 的奇偶性相同,则对于位置 l,l+2,l+4,...,rl,l+2,l+4,\,...\,,r ,它们出现的次数均为奇数次,即区间 [l,r][l,r] 中所有与 ll 奇偶性相同的位置均贡献了答案。

所以我们直接维护两个树状数组,一个维护偶数位上的值,一个维护奇数位上的值,在查询时查询相应奇偶性树状数组的区间异或和即可

coding:

树状数组类:

class fenwick_tree
{
private:
    int n;
    vector<int> bit;

public:
    fenwick_tree(const int n)
    {
        this->n = n;
        bit.resize(n + 1, 0);
    }

    int lowbit(int x)
    {
        return x & (-x);
    }

    void update(int idx, int val)
    {
        while (idx <= n)
        {
            bit[idx] ^= val;
            idx += lowbit(idx);
        }
    }

    void initialize(vector<int> arr)
    {
        for (int i = 1; i <= n; i++)
            update(i, arr[i]);
    }

    int query(int idx)
    {
        int res = 0;
        while (idx)
        {
            res ^= bit[idx];
            idx -= lowbit(idx);
        }

        return res;
    }

    int query_range(int l, int r)
    {
        return query(r) ^ query(l - 1);
    }
};

主函数:

cin >> n >> q;
    vector<int> odd(n + 1), even(n + 1);
    for (int i = 1; i <= n; i++)
    {
        if (i % 2)
            cin >> odd[i / 2 + 1];
        else
            cin >> even[i / 2];
    }

    fenwick_tree odd_ft(odd.size() - 1), even_ft(even.size() - 1);
    odd_ft.initialize(odd);
    even_ft.initialize(even);

    int op;
    while (q--)
    {
        cin >> op;

        if (op == 1)
        {
            int i, j;
            cin >> i >> j;

            if (i % 2)
            {
                i = i / 2 + 1;
                int old_val = odd_ft.query_range(i, i);
                odd_ft.update(i, old_val ^ j);
            }
            else
            {
                i /= 2;
                int old_val = even_ft.query_range(i, i);
                even_ft.update(i, old_val ^ j);
            }
        }
        else
        {
            int l, r;
            cin >> l >> r;
            int len = r - l + 1;

            if (len % 2 == 0)
                cout << "0\n";
            else
            {
                int res;
                if (l % 2)
                {
                    l = l / 2 + 1, r = r / 2 + 1;
                    res = odd_ft.query_range(l, r);
                }
                else
                {
                    l /= 2, r /= 2;
                    res = even_ft.query_range(l, r);
                }

                cout << res << "\n";
            }
        }
    }