概念
概念的话感觉就不是很好理解,但是满足树状数组的功能特性:对数组进行简化(因为C数组的辅助),使得之后优化遍历的时间复杂度到log。因此,二维树状数组其实也就这个用,只是之前是针对一维,现在是针对二维。
百度百科这样写的,其实看不看懂问题不大:
模板
主要是要记住下面的方法!
单点更新 和 区间查询。
其实A数组要不要都无所谓,因为C数组的更新其实就代表了A数组的更新。看题意。
区间查询操作一般是为了用于“子矩阵查询”,公式如上。
其实很好理解,区间查询sum(i,j)指的是从矩阵左上方拉到A[i][j]处的矩形,而把它修剪一下,就能得到想要的子矩阵。
画了个图理解:
黑色是整个矩阵,红色是想求的子矩阵,灰色是减去的矩阵,棕色是重新加上的矩阵(因为被多剪了一次)。
(这张图结合上面的公式理解即可)
例题:
思路:
直接套模板即可。
细节注意:因为用scanf比用cin快,而且要查询那么多次,所以我用的scanf,然后发现了一个知识点:如果出现多个scanf连用,一般是没问题的,但是如果,在用完一个scanf之后,接下来是一个需要输入“%c”的scanf,就要特别注意了!为什么?因为scanf的输入会在缓冲区留下一个空白字符(你敲的空格或回车),而如果下一个scanf是吃“%c”的话,吃掉的就会是这个空白字符,整个程序就乱了呀!所以,需要在吃"%c"的scanf之前加一个 getchar() 吃掉先前的空白字符。
(在连用scanf 或 循环体中 ,如果有吃“%c”的scanf时,一定要注意!!!否则很难找到这个问题源)
代码:
#include<iostream> #include<bits/stdc++.h> using namespace std; const int maxn=1010; int c[maxn][maxn]; int n; void add(int i,int j,int v) { for(int x=i;x<=n;x+=x&(-x)) { for(int y=j;y<=n;y+=y&(-y)) c[x][y]+=v; } } int sum(int i,int j) { int res=0; for(int x=i;x>0;x-=x&(-x)) { for(int y=j;y>0;y-=y&(-y)) res+=c[x][y]; } return res; } int main() { cin>>n; int q; scanf("%d",&q); char C; while(q--) { getchar(); //吃掉空白字符!!! scanf("%c",&C); if(C=='C') { int a,b,c; scanf("%d%d%d",&a,&b,&c); add(a,b,c); } else { int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); printf("%d\n",sum(x2,y2)-sum(x2,y1-1)-sum(x1-1,y2)+sum(x1-1,y1-1)); } } return 0; }