首页 > 编程语言 > 详细

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

时间:2017-05-24 23:08:25      阅读:277      评论:0      收藏:0      [点我收藏+]

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 }

 

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

原文:http://www.cnblogs.com/running-coder-wfh/p/6901437.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!