树状数组的基本操作
理解:二进制末位次方为该位置管辖的范围,无法管辖的范围就是该数减去该二进制末位次方,递推往上,直到得到[1,n]的管辖点,然后相加。某个位置修改,会导致管辖它的点也相应被修改,这关键就是二进制的进位来更新管辖它的点,2^0一定被2^1管辖,2^1一定被2^2管辖。因为二进制的独特性,把这些最关键也是最基本的操作降到了log(n)。
一、一维树状数组的基本操作
转载:https://www.cnblogs.com/xenny/p/9739600.html
①单点更新,区间求和
模板:https://www.luogu.com.cn/problem/P3374
1 #include <iostream> 2 #include <algorithm> 3 #include <map> 4 #include <queue> 5 #include <string> 6 #include <stack> 7 #include <functional> 8 #include <vector> 9 #include <numeric> 10 #include <list> 11 #include <cstdio> 12 #include <cstring> 13 #include <cmath> 14 using namespace std; 15 #define ll long long 16 #define pb push_back 17 #define fi first 18 #define se second 19 20 const int N = 5e5+10; 21 int arr[N]; 22 int n,m; 23 24 inline int lowbit(int x){ 25 return x&(-x); 26 } 27 28 void update(int x,int v){ 29 while(x <= n){ 30 arr[x] += v; 31 x += lowbit(x); 32 } 33 } 34 35 int sum(int x){ 36 int res = 0; 37 while(x){ 38 res += arr[x]; 39 x -= lowbit(x); 40 } 41 return res; 42 } 43 44 void solve(){ 45 scanf("%d%d",&n,&m); 46 for(int i = 1; i <= n; ++i){ 47 int x; 48 scanf("%d",&x); 49 update(i,x); 50 } 51 int op,x,y; 52 while(m--){ 53 scanf("%d%d%d",&op,&x,&y); 54 if(op == 1){ 55 update(x,y); 56 }else { 57 printf("%d\n",sum(y) - sum(x-1)); 58 } 59 } 60 } 61 62 int main(){ 63 64 solve(); 65 66 return 0; 67 }
②区间修改,单点求值
模板:https://www.luogu.com.cn/problem/P3368
1 #include <iostream> 2 #include <algorithm> 3 #include <map> 4 #include <queue> 5 #include <string> 6 #include <stack> 7 #include <functional> 8 #include <vector> 9 #include <numeric> 10 #include <list> 11 #include <cstdio> 12 #include <cstring> 13 #include <cmath> 14 using namespace std; 15 #define ll long long 16 #define pb push_back 17 #define fi first 18 #define se second 19 20 const int N = 5e5+10; 21 int c[N],a[N]; 22 int n,m; 23 24 inline int lowbit(int x){ 25 return x&(-x); 26 } 27 28 void update(int x,int v){ 29 while(x <= n){ 30 c[x] += v; 31 x += lowbit(x); 32 } 33 } 34 35 int sum(int x){ 36 int res = 0; 37 while(x){ 38 res += c[x]; 39 x -= lowbit(x); 40 } 41 return res; 42 } 43 44 void solve(){ 45 scanf("%d%d",&n,&m); 46 for(int i = 1; i <= n; ++i){ 47 scanf("%d",a+i); 48 update(i,a[i] - a[i-1]); 49 } 50 int op; 51 while(m--){ 52 scanf("%d",&op); 53 if(op == 1){ 54 int x,y,k; 55 scanf("%d%d%d",&x,&y,&k); 56 update(x,k); 57 update(y+1,-k); 58 }else{ 59 int x; 60 scanf("%d",&x); 61 printf("%d\n",sum(x)); 62 } 63 } 64 } 65 66 int main(){ 67 68 solve(); 69 70 return 0; 71 }
③区间修改,区间求值
模板:https://vjudge.net/problem/POJ-3468
#include <iostream> #include <algorithm> #include <map> #include <queue> #include <string> #include <stack> #include <vector> #include <list> #include <cstdio> #include <cstring> #include <cmath> using namespace std; #define ll long long #define pb push_back #define fi first #define se second const int N = 1e5+10; ll sum_1[N],sum_2[N],a[N]; int n; inline int lb(int x){ return x&(-x); } void update(int inx,int v){ int x = inx; while(inx <= n){ sum_1[inx] += v; sum_2[inx] += (ll)v*(x-1); inx += lb(inx); } } ll sum(int inx){ ll res = 0; int x = inx; while(inx){ res += (ll)x*sum_1[inx] - sum_2[inx]; inx -= lb(inx); } return res; } void solve(){ int q; scanf("%d%d",&n,&q); for(int i = 1; i <= n; ++i){ scanf("%lld",a+i); update(i,a[i] - a[i-1]); } char op[10]; int a,b,c; while(q--){ scanf("%s",op); if(op[0] == 'Q'){ scanf("%d%d",&a,&b); ll ans = sum(b) - sum(a-1); printf("%lld\n",ans); }else{ scanf("%d%d%d",&a,&b,&c); update(a,c); update(b+1,-c); } } } int main(){ // ios::sync_with_stdio(false); // cin.tie(0); cout.tie(0); solve(); return 0; }
二、二维树状数组的基本操作
①单点修改,区间求值
模板:https://www.acwing.com/problem/content/1271/
1 #include <iostream> 2 #include <algorithm> 3 #include <map> 4 #include <queue> 5 #include <string> 6 #include <stack> 7 #include <functional> 8 #include <vector> 9 #include <numeric> 10 #include <list> 11 #include <cstdio> 12 #include <cstring> 13 #include <cmath> 14 using namespace std; 15 #define ll long long 16 #define pb push_back 17 #define fi first 18 #define se second 19 20 const int N = 1e3+100; 21 int a[N][N]; 22 int c[N][N]; 23 int n,m; 24 25 inline int lb(int x){ 26 return x&(-x); 27 } 28 29 void update(int x, int y, int v){ 30 a[x][y] += v; 31 for(int i = x; i <= n; i += lb(i)) 32 for(int j = y; j <= n; j += lb(j)) 33 c[i][j] += v; 34 } 35 36 int sum(int x,int y){ 37 int res = 0; 38 for(int i = x; i >= 1; i -=lb(i)) 39 for(int j = y; j >= 1; j -= lb(j)) 40 res += c[i][j]; 41 return res; 42 } 43 44 void solve(){ 45 scanf("%d",&n); 46 int op; 47 while(scanf("%d",&op) && op != 3){ 48 if(op == 1){ 49 int x,y,k; 50 scanf("%d%d%d",&x,&y,&k); 51 ++x;++y; 52 swap(x, y); 53 update(x,y,k); 54 }else if(op == 2){ 55 int x1,x2,y1,y2; 56 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 57 ++x1;++x2;++y1;++y2; 58 swap(x1,y1); swap(x2,y2); 59 int tot = sum(x2,y2) - sum(x1-1,y2) - sum(x2,y1-1) + sum(x1-1,y1-1); 60 printf("%d\n",tot); 61 }else break; 62 } 63 } 64 65 int main(){ 66 67 solve(); 68 69 return 0; 70 }
②区间修改,单点求值
题目:https://vjudge.net/problem/POJ-2155
题目解析:https://wenku.baidu.com/view/1e51750abb68a98271fefaa8.html
1 #include <iostream> 2 #include <algorithm> 3 #include <map> 4 #include <queue> 5 #include <string> 6 #include <stack> 7 #include <functional> 8 #include <vector> 9 #include <numeric> 10 #include <list> 11 #include <cstdio> 12 #include <cstring> 13 #include <cmath> 14 using namespace std; 15 #define ll long long 16 #define pb push_back 17 #define fi first 18 #define se second 19 20 const int N = 1e3+100; 21 int c[N][N]; 22 int n; 23 24 inline int lb(int x){ 25 return x&(-x); 26 } 27 28 void update(int x,int y){ 29 for(int i = x; i <= n; i += lb(i)) 30 for(int j = y; j <= n; j += lb(j)) 31 ++c[i][j]; 32 } 33 34 int sum(int x,int y){ 35 int res = 0; 36 for(int i = x; i >= 1; i -= lb(i)) 37 for(int j = y; j >= 1; j -= lb(j)) 38 res += c[i][j]; 39 40 return res; 41 } 42 43 void solve(){ 44 int T,q; 45 scanf("%d",&T); 46 while(T--){ 47 memset(c,0,sizeof(c)); 48 scanf("%d%d",&n,&q); 49 char op[10]; 50 while(q--){ 51 scanf("%s",op); 52 if(op[0] == 'C'){ 53 int x1,x2,y1,y2; 54 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 55 update(x1,y1); update(x1,y2+1); update(x2+1,y1); update(x2+1,y2+1); 56 }else{ 57 int x,y; 58 scanf("%d%d",&x,&y); 59 int ans = sum(x,y)%2 == 0 ? 0 : 1; 60 printf("%d\n",ans); 61 } 62 } 63 printf("\n"); 64 } 65 } 66 67 int main(){ 68 69 solve(); 70 71 return 0; 72 }
1