[模板]洛谷T3368 树状数组 模板2

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
",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 }

6.25更正:

上面的代码关于结点原值查找部分进行了无用的累赘操作,现更正如下:

 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 
12 using namespace std;
13 
14 void update(int,int,int);
15 int query(int);
16 
17 int c[500010];
18 int addv[500010];
19 
20 int n,m,i;
21 int f,x,y,k;
22 
23 int main(){
24     scanf("%d%d",&n,&m);
25     
26     for(i=1;i<=n;i++)scanf("%d",&c[i]);
27     
28     for(i=1;i<=m;i++){
29         scanf("%d",&f);
30         
31         if(f==1){
32             scanf("%d%d%d",&x,&y,&k);
33             update(x,y,k);
34         }
35         else{
36             scanf("%d",&x);
37             printf("%d
",query(x));
38         }
39     }
40     
41     return 0;
42 }
43 
44 void update(int a,int b,int x){
45     while(b>=a){
46         addv[b]+=x;
47         b-=b&-b;
48     }
49     a--;
50     while(a>b){
51         addv[a]-=x;
52         a-=a&-a;
53     }
54 }
55 
56 int query(int p){
57     int sum=c[p];
58     while(p<=n){
59         sum+=addv[p];
60         p+=p&-p;
61     }
62     return sum;
63 }
原文地址:https://www.cnblogs.com/running-coder-wfh/p/6901437.html