利用了二进制,二分的思想的一个很巧妙的数据结构,一个lowbit(x):二进制表示下的最右边的一个1开始对应的数值。
那么如果一个节点的为x左孩子,父亲节点就是 x + lowbit(x),如果是右孩子,父亲节点是 x-lowbit(x);
图中白条部分就是辅助数组C对应的最底下的和。
1、那么一个前缀和有是怎样的呢?
就是从最底下开始,边往上走,边往左走。
2、修改单点呢?
从最底下开始,边往上走,边往下走。
LA2191:
题目链接:https://vjudge.net/contest/147973#problem/A
题意:
先给出一个数组,然后有两个操作
S x y 把第x个数改成y
M x y计算x~y个数的和
Source Code:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 inline int lowbit(int x) 6 { 7 return x&-x; 8 } 9 10 struct FenwickTree 11 { 12 int n; 13 vector<int> C; 14 15 void resize(int n) 16 { 17 this->n = n; 18 C.resize(n+10); 19 } 20 void clear() 21 { 22 fill(C.begin(), C.end(), 0); 23 } 24 25 // 计算A[1]+A[2]+...+A[x] (x<=n) 26 int sum(int x) 27 { 28 int ret = 0; 29 while(x > 0) 30 { 31 ret += C[x]; 32 x -= lowbit(x); 33 } 34 return ret; 35 } 36 37 // A[x] += d (1<=x<=n) 38 void add(int x, int d) 39 { 40 while(x <= n) 41 { 42 C[x] += d; 43 x += lowbit(x); 44 } 45 } 46 }; 47 48 FenwickTree f; 49 const int maxn = 200000+5; 50 int a[maxn]; 51 52 int main() 53 { 54 // freopen("in.txt","r",stdin); 55 int n; 56 int cases = 0; 57 while(scanf("%d",&n),n) 58 { 59 if(cases>0) puts(""); 60 printf("Case %d:\n",++cases); 61 f.resize(n); 62 f.clear(); 63 for(int i=1; i<=n; i++) 64 { 65 scanf("%d",&a[i]); 66 f.add(i,a[i]); 67 } 68 69 char op[5]; 70 while(scanf("%s",op)!=EOF) 71 { 72 if(!strcmp(op,"END")) 73 break; 74 if(op[0]=='M') 75 { 76 int x,y; 77 scanf("%d%d",&x,&y); 78 printf("%d\n",f.sum(y)-f.sum(x-1)); 79 } 80 if(op[0]=='S') 81 { 82 int x,y; 83 scanf("%d%d",&x,&y); 84 int add = y - a[x]; 85 a[x] = y; 86 f.add(x,add); 87 } 88 } 89 } 90 91 return 0; 92 }