CF341D-Iahub and Xors

题目

一个\(n\times n\)的零矩阵\(a\)\(m\)次操作:

  • \(x_0\ y_0\ x_1\ y_1\ c\),对\(a[x][y],x\in[x_0,x_1],y\in[y_0,y_1]\)异或上一个数\(c\)
  • \(x_0\ y_0\ x_1\ y_1\),询问这个子矩阵的异或和

\(n\le 1000,m\le 10^5,0\le c<2^{62}\)

分析

树状数组的妙用!关键还是在异或的性质和处理矩阵的方法。

首先考虑矩阵异或,单点查询,那么对于一个修改\((x_0,y_0,x_1,y_1,c)\),如果我们对\((x_0,y_0),(x_0,y_1+1),(x_1+1,y_0),(x_1+1,y_1+1)\)都异或上\(c\),那么一个结论就是一个点\((x,y)\)的值就是\((1,1,x,y)\)的异或和。(画一画图就知道了)

现在是询问子矩阵的异或和,显然首先转化为求任意的\((1,1,x,y)\)的异或和。

在之前那种修改方式下,一个点的点值就是\((1,1,x,y)\)的异或和,那么要求\((1,1,x,y)\)的异或和,我们就把这些异或和异或起来。

考虑每个点的出现次数,我们会发现,对于一个点\((x_0,y_0)\),它在总异或中出现奇数次当且仅当\((x-x_0+1)(y-y_0+1)\)为奇数。

例如我们统计\((1,1,3,4)\)的异或和的异或和,我们只用统计\((1,2),(1,4),(3,2),(3,4)\)这几个点的值。

于是对于每一种\((x,y)\)的奇偶情况,我们开一个二维树状数组来进行单点修改,前缀异或和查询即可(二维树状数组就是一维树状数组的每个点都是一个树状数组)。

代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long giant;
int read() {
    int x=0,f=1;
    char c=getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
    for (;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
const int maxn=1e3+2;
int n,m;
inline int lowbit(int x) {return x&-x;}
struct BIT {
    giant c[maxn][maxn];
    void change(int x,int y,giant d) {
        for (;x<=n+1;x+=lowbit(x)) for (int i=y;i<=n+1;i+=lowbit(i)) c[x][i]^=d;
    }
    giant query(int x,int y) {
        giant ret=0;
        for (;x;x-=lowbit(x)) for (int i=y;i;i-=lowbit(i)) ret^=c[x][i];
        return ret;
    }
} t[2][2];
giant get(int x,int y) {
    giant ret=t[x&1][y&1].query((x+1)>>1,(y+1)>>1);
}
giant get(int x1,int y1,int x2,int y2) {
    giant a=get(x1-1,y1-1);
    giant b=get(x1-1,y2);
    giant c=get(x2,y1-1);
    giant d=get(x2,y2);
    giant ret=a^b^c^d;
    return ret;
}
void change(int x,int y,giant c) {
    t[x&1][y&1].change((x+1)>>1,(y+1)>>1,c);
}
void change(int x1,int y1,int x2,int y2,giant c) {
    change(x1,y1,c);
    change(x1,y2+1,c);
    change(x2+1,y1,c);
    change(x2+1,y2+1,c);
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("test.in","r",stdin);
#endif
    n=read(),m=read();
    while (m--) {
        int o=read(),x1=read(),y1=read(),x2=read(),y2=read();
        giant c;
        if (o==2) scanf("%lld",&c);
        if (o==1) printf("%lld\n",get(x1,y1,x2,y2)); else change(x1,y1,x2,y2,c);
    }
    return 0;
}

转载于:https://www.cnblogs.com/owenyu/p/7152495.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值