[Codeforces 341D] Iahub and Xors (二维树状数组)

本文介绍了一道经典的二维树状数组题目,通过结合异或操作实现矩阵区域的更新和查询。文章详细解释了如何利用四个树状数组来处理奇偶位置的不同影响,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

Codeforces 341D


题意

给出一个n*n的矩阵,初始值均为0,然后m组操作,可以给出一个矩形区域,使其中元素都异或某值,也可以给出矩形区域,查询其中所有元素的异或值。


题解

二维树状数组的经典题目,跟异或操作结合。
二维树状数组的基本功能是单点更新和区间查询,当然只能查询某点到(1, 1)点的值,也可以利用差分的思想改成区间更改和单点查询。这里是异或操作,事实上跟加减法的运算规律类似,也是可叠加的。
考虑一维树状数组的区间异或和单点查询(注意这里不是题意中要求的区间查询),想对一个区间进行异或,第一反应是对区间端点进行add操作(就想利用差分对加减法所做的那样),查询的时候get区间即可,看似是对的。但是异或和加减法不同,加减法是完全的叠加,但是异或却是奇数个元素叠加,偶数个元素消除的。所以我们在记录区间内的异或操作时,需要按照元素的奇偶进行分类,比如我们利用add在区间的x位置放置了一个异或元素,如果x是奇数,那么它能影响到的只有[x, n]之间同为奇数位置的元素,对偶数位置的元素是没有影响的,因为消除了。我们只要建两个树状数组分别记录奇偶两种元素下标提供的异或值即可,因为是互相不影响的。但是我们现在要求的是区间查询,事实上对异或操作而言,单点查询x就是[1, x]的区间查询,因为x之前的影响两两消除了。
推广到2维情况也一样,不过这时候需要对矩阵中的元素个数按奇偶分类,就需要建4个树状数组了。


代码
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long lint;
#define maxn (1010)
inline lint lowbit(lint x) { return x&-x; }
lint c[2][2][maxn][maxn];
void add(int x, int y, int val, int n)
{
    for(int i = x; i <= n; i += lowbit(i))
    {
        for(int j = y; j <= n; j += lowbit(j))
        c[x&1][y&1][i][j] ^= val;
    }
}
lint get(int x, int y)
{

    lint o = 0;
    for(int i = x; i; i -= lowbit(i))
    {
        for(int j = y; j; j -= lowbit(j))
        o ^= c[x&1][y&1][i][j];
    }
    return o;
}
int main()
{
    int n, m;
    cin >> n >> m;
    int op, x1, x2, y1, y2;
    lint val;
    while(m--)
    {
        scanf("%d%d%d%d%d", &op, &x1, &y1, &x2, &y2);
        if(op == 1)
        {
            val = 0;
            val ^= get(x2, y2);
            val ^= get(x1 - 1, y2);
            val ^= get(x2, y1 - 1);
            val ^= get(x1 - 1, y1 - 1);
            cout << val << endl;
        }
        else
        {
            cin >> val;
            add(x1, y1, val, n);
            add(x1, y2 + 1, val, n);
            add(x2 + 1, y1, val, n);
            add(x2 + 1, y2 + 1, val, n);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值