POJ2155/LNSYOJ113 Matrix【二维树状数组+差分】【做题报告】

这道题是一个二维树状数组,思路十分神奇,其实还是挺水的

题目描述

给定一个N∗NN∗N的矩阵AA,其中矩阵中的元素只有0或者1,其中A[i,j]A[i,j]表示矩阵的第i行和第j列(1≤i,j≤N)(1≤i,j≤N),初始矩阵元素都是0。在矩阵上进行TT次操作,操作有以下两种:

(1)格式为C x1 y1 x2 y2(1≤x1≤x2≤n,1≤y1≤y2≤n)C x1 y1 x2 y2(1≤x1≤x2≤n,1≤y1≤y2≤n) ,其中CC为字符“C”,表示把以(x1,y1)(x1,y1)为左上角,(x2,y2)(x2,y2)为右下角的这个矩形内的每一个数字同1异或

(2)格式为Q x y(1≤x,y≤n)Q x y(1≤x,y≤n),其中QQ为字符“Q”, 表示询问A[x,y]A[x,y]的值。

输入格式

第一行输入XX,表示X组测试数据

接下来每一组测试数据第一行包含两个整数NN和TT,其中NN表示矩阵的大小,TT表示对矩阵操作次数。

接下来TT行形式如 "Q x y" or "C x1 y1 x2 y2"操作,见题目中描述

输出格式

对于每个Q x yQ x y的操作输出答案A[x,y]A[x,y]。

样例一

input

1
2 10
C 2 1 2 2
Q 2 2
C 2 1 2 1
Q 1 1
C 1 1 2 1
C 1 2 1 2
C 1 1 2 2
Q 1 1
C 1 1 2 1
Q 2 1

output

1
0
0
1

限制与约定

对于30%的数据N≤100,T≤3000N≤100,T≤3000

对于50%的数据N≤500,T≤20000N≤500,T≤20000

对于100%的数据N≤1000,T≤50000,X≤10N≤1000,T≤50000,X≤10

时间限制:1s1s

空间限制:256MB

首先二维树状数组的标准写法

 1 #define lowbit(a) (a)&(-a)
 2 void change(int px,int py,int val)
 3 {
 4     for(int i=px;i<=n;i+=lowbit(i))
 5         for(int j=py;j<=n;j+=lowbit(j))
 6             tree[i][j]=(tree[i][j]+val)%2;
 7 }
 8 int ask(int px,int py)
 9 {
10     int ans=0;
11     for(int i=px;i;i-=lowbit(i))
12         for(int j=py;j;j-=lowbit(j))
13             ans=(ans+tree[i][j])%2;
14     return ans;
15 }

就是一维树状数组加了一层循环,很好理解的233

这道题需要打个差分,差分个人理解就是把正常一个数组i与i-1做差,得到的一个差分数组,然后查询时累加前缀和,这么做有很多方便的地方,比如洛谷的树状数组2

来介绍一下差分

设数组a[]={1,6,8,5,10},那么差分数组b[]={1,5,2,-3,5}

也就是说b[i]=a[i]-a[i-1];(a[0]=0;),那么a[i]=b[1]+....+b[i];(这个很好证的)。

假如区间[2,4]都加上2的话

a数组变为a[]={1,8,10,7,10},b数组变为b={1,7,2,-3,3};

发现了没有,b数组只有b[2]和b[5]变了,因为区间[2,4]是同时加上2的,所以在区间内b[i]-b[i-1]是不变的.

所以对区间[x,y]进行修改,只用修改b[x]与b[y+1]:

b[x]=b[x]+k;b[y+1]=b[y+1]-k;


以上就是差分的应用,对于区间修改时应该想到差分,

比如这道题,就是矩阵的子矩阵修改,这种方法就非常nice

看下面这张图,修改绿色部分,只需把红色的都+1%2,再累加前缀和能满足(图片出处在水印233)

其实差分区间修改都可以理解为,比如修改(x,y)全部加2,只要把差分数组中x位置,然后再把y+1减2,就能完美解决,配上树状数组,这样修改和查询就就是O(log(n)),时间复杂度满足

注意要清数组清数组清数组清数组清数组,没清数组只A了一个点QAQ

最后放代码

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define lowbit(a) (a)&(-a)
 5 int t,n,k,x,y,z,w;
 6 int tree[1111][1111];
 7 char opt[5];
 8 void change(int px,int py,int val)
 9 {
10     for(int i=px;i<=n;i+=lowbit(i))
11         for(int j=py;j<=n;j+=lowbit(j))
12             tree[i][j]=(tree[i][j]+val)%2;
13 }
14 int ask(int px,int py)
15 {
16     int ans=0;
17     for(int i=px;i;i-=lowbit(i))
18         for(int j=py;j;j-=lowbit(j))
19             ans=(ans+tree[i][j])%2;
20     return ans;
21 }
22 int main()
23 {
24     scanf("%d",&t);
25     while(t--)
26     {
27         memset(tree,0,sizeof(tree));
28         scanf("%d%d",&n,&k);
29         for(int i=1;i<=k;i++)
30         {
31             scanf("%s",opt);
32             if(opt[0]==‘C‘)
33             {
34                 scanf("%d%d%d%d",&x,&y,&z,&w);
35                 change(x,y,1),change(z+1,w+1,1),change(x,w+1,1),change(z+1,y,1);
36             }else if(opt[0]==‘Q‘)
37             {
38                 scanf("%d%d",&x,&y);
39                 printf("%d\n",ask(x,y));
40             }
41         }
42     }
43     return 0;
44 }

By  浅夜_MISAKI

原文地址:https://www.cnblogs.com/Qin-Wei-Kai/p/10052168.html

时间: 2024-08-03 19:09:13

POJ2155/LNSYOJ113 Matrix【二维树状数组+差分】【做题报告】的相关文章

POJ2155 Matrix 二维树状数组的应用

有两种方法吧,一个是利用了树状数组的性质,很HDU1556有点类似,还有一种就是累加和然后看奇偶来判断答案 题意:给你一个n*n矩阵,然后q个操作,C代表把以(x1,y1)为左上角到以(x2,y2)为右下角的矩阵取反,意思就是矩阵只有0,1元素,是0的变1,是1的变0,Q代表当前(x,y)这个点的状况,是0还是1? 区间修改有点特别,但是若区间求和弄懂了应该马上就能懂得: add(x2,y2,1); add(x2,y1,-1);//上面多修改了不需要的一部分,所以修改回来 add(x1,y2,-

Matrix 二维树状数组的第二类应用

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 17976   Accepted: 6737 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

[poj2155]Matrix(二维树状数组)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 25004   Accepted: 9261 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

【POJ2155】【二维树状数组】Matrix

Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1 <= i, j <= N). We can change the matrix in the following way. Given a rectangle whose upp

POJ2155 Matrix 二维树状数组应用

一个N*N(1<=N<=1000)的矩阵,从(1,1)开始,给定一些操作C和一些查询Q,一共K条(1<=K<=50000): C x1,y1,x2,y2 表示从x1行y1列到x2行y2列的元素全部反转(0变成1,1变成0): Q x y表示询问x行y列的元素是0还是1. 题目乍一看感觉还是很难,如果能记录每一个元素的状态值,那答案是显而易见的,但是元素过多,如果每次都对每一个元素进行更新状态的话,复杂度太高.实际上只要记录边界的特定坐标的反转次数,最好的选择那就是二维树状数组了.

POJ 2155 Matrix(二维树状数组,绝对具体)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

POJ 2155 Matrix(二维树状数组,绝对详细)

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 20599   Accepted: 7673 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1

二维树状数组(水题) POJ1195

前段时间遇到线段树过不了,树状数组却过了的题.(其实线段树过得了的) 回忆了下树状数组. 主要原理,还是二进制位数,每一项的和表示其为它的前((最后一位1及其后)的二进制数)和,可从二进制图来看.(用线段树想一想其实只是线段树编号不同而已,本质类似) 写了下二维树状数组,几乎和一维相同,也没必要不同. #include <cstdio> #include <cstring> int l,r,x,y,n,a,p,sum[1125][1125]; inline int lowbit(i

POJ 2155 Matrix 二维树状数组

Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 19174   Accepted: 7207 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1