[模板]洛谷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\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 }
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\n",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 }