1.对于区间修改:
直接修改数组c[],即进行n次add,肯定会TLE;
于是在此引入一个新数组:addv[],addv[i]指的是以结点i为根的树的所有元素加上addv[i]。
设将区间[a,b]中每个数加上x,
则只需自b向左,将相应的addv[]加上x,再自a-1向左,将多修改的结点的addv[]减去x即可。
2.对于单点查询:
设查询结点i,则其原值为:
(以结点i为根的树的所有元素的和)-(此树中除结点i之外的所有节点的和);
然后从结点i向树根遍历,将遍历到的节点的addv[]值加给之前已计算出的结点i的原值,最终结果就是结点i现在的值。
代码如下:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<ctime> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<string> 8 #include<stack> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 void add(int,int); 13 void update(int,int,int); 14 int query(int); 15 int c[500010]; 16 int addv[500010]; 17 int n,m; 18 int i,t; 19 int f; 20 int x,y,k; 21 int main(){ 22 scanf("%d%d",&n,&m); 23 for(i=1;i<=n;i++){ 24 scanf("%d",&t); 25 add(i,t); 26 } 27 for(i=1;i<=m;i++){ 28 scanf("%d",&f); 29 if(f==1){ 30 scanf("%d%d%d",&x,&y,&k); 31 update(x,y,k); 32 } 33 else{ 34 scanf("%d",&x); 35 printf("%d\n",query(x)); 36 } 37 } 38 return 0; 39 } 40 void add(int p,int x){ 41 while(p<=n){ 42 c[p]+=x; 43 p+=p&-p; 44 } 45 } 46 void update(int a,int b,int x){ 47 while(b>=a){ //区间加 48 addv[b]+=x; 49 b-=b&-b; 50 } 51 a--; 52 while(a>b){ //区间减 53 addv[a]-=x; 54 a-=a&-a; 55 } 56 } 57 int query(int p){ 58 int p1=p-(p&-p); 59 int p2=p-1; 60 int t=c[p]; 61 while(p2>p1){ 62 t-=c[p2]; 63 p2-=p2&-p2; 64 } //计算结点原值 65 while(p<=n){ 66 t+=addv[p]; 67 p+=p&-p; 68 } //追加addv[] 69 return t; 70 }
原文:http://www.cnblogs.com/running-coder-wfh/p/6901437.html