树状数组总结
首先我们来说一下这个算法的正确性,从一维开始吧,我们假设有两个点,i,i1,i一直加上lowbit(i),而i1一直减去lowbit(i1),这是两个严格单调的序列,如果这两个序列有交点,则有且只有一个交点k,则从i~i1这一段的和可以用c[k]来记录(且只有一个c[k]满足)。
二维树状数组也是类似,首先明确二维的c[i][j]记录的是以( i,j )为右下,( i-lowbit(i)+1 ,j-lowbit(j)+1 )为左上的矩形中所含元素的和( 至于为什么不能理解为一排一排的一维树状数组,是因为这样时间复杂度会从(logn)^2变为nlogn),假设有一个点( i1 , j1 ),i 与 i1 可以确定好交点的横坐标, 而 j 与 j1 可以确定该交点宗坐标,则交点确定。
例题:
Problem 1. matsum
Input file: matsum.in
Output file: matsum.out
Time limit: 1 second
给出N M 的一个矩阵,初始时全部元素为0,有两种操作:
? modify x y d:将位置(x,y) 的值加上d。
? query x1 y1 x2 y2:询问(x1,y1)-(x2,y2) 这个矩形的和。1
Input
第1 行,3 个整数N;M;Q,分别表示矩阵的行数、列数及询问数。
接下来Q 行,每行是上面两种操作之一。
Output
对于每个询问,输出询问结果。
Sample
matsum.in matsum.out
2 2 4
modify 1 1 4
query 1 1 2 2
modify 2 2 -4
query 1 1 2 2
40
Note
? 对于30% 的数据,1 N;M;Q 500;
? 对于另外30% 的数据,N = 1; 1 M;Q 105;
? 对于另外40% 的数据,1 N;M 103; 1 Q 105;
? 对于所有数据,jdj 100; 1 x N; 1 y M; 1 x1 x2 N; 1 y1 y2 M ;
#include <cstdio> int n, m, q; struct Case1 { int bit[100010]; void modify( int p, int d ) { for( int i = p; i <= m; i += i & -i ) bit[i] += d; } int query( int r ) { int rt = 0; for( int i = r; i; i -= i & -i ) rt += bit[i]; return rt; } int query( int l, int r ) { return query(r) - query(l-1); } void solve() { while (q--) { char ss[100]; scanf( "%s", ss ); if( ss[0] == ‘m‘ ) { int x, y, d; scanf( "%d%d%d", &x, &y, &d ); modify( y, d ); } else { int x1, y1, x2, y2; scanf( "%d%d%d%d", &x1, &y1, &x2, &y2 ); printf( "%d\n", query(y1,y2) ); } } } }case1; struct Case2 { int bit[1100][1100]; void modify( int x, int y, int d ) { for( int i = x; i <= n; i += i & -i ) for( int j = y; j <= m; j += j & -j ) bit[i][j] += d; } int query( int x, int y ) { int rt = 0; for( int i = x; i; i -= i & -i ) for( int j = y; j; j -= j & -j ) rt += bit[i][j]; return rt; } int query( int x1, int y1, int x2, int y2 ) { return query(x2,y2) - query(x1-1,y2) - query(x2,y1-1) + query(x1-1,y1-1); } void solve() { while(q--) { char ss[100]; scanf( "%s", ss ); if( ss[0] == ‘m‘ ) { int x, y, d; scanf( "%d%d%d", &x, &y, &d ); modify( x, y, d ); } else { int x1, y1, x2, y2; scanf( "%d%d%d%d", &x1, &y1, &x2, &y2 ); printf( "%d\n", query(x1,y1,x2,y2) ); } } } }case2; int main() { freopen ( "matsum.in", "r", stdin ) ; freopen ( "matsum.out", "w", stdout ) ; scanf( "%d%d%d", &n, &m, &q ); if( n == 1 ) case1.solve(); else case2.solve(); }