[关闭]
@zhshh 2018-07-22T08:54:17.000000Z 字数 1637 阅读 878

树状数组

@zhshh cpp OI 数据结构


一维树状数组

单点更改,区间求和

回到顶部

  1. #include <iostream>
  2. #define MX 500010
  3. #define lowbit(x) (x&(-x))
  4. using namespace std;
  5. int n;
  6. int c[1000],a[1000];
  7. void add(int x,int y){//对于节点x加上y
  8. for(;x<=n;x+=(lowbit(x))){
  9. c[x]+=y;
  10. }
  11. }
  12. int sum(int x){//计算1..x的求和,类似于前缀和
  13. int ans=0;
  14. for(;x>=1;x-=lowbit(x)){
  15. ans+=c[x];
  16. }
  17. return ans;
  18. }
  19. int query(int left,int right){//区间查询,就是利用前缀和的思想
  20. return sum(right)-sum(left-1);
  21. }
  22. int main(){
  23. cin>>n;
  24. for(int i=1;i<=n;i++){
  25. cin>>a[i];
  26. update(i,a[i]);
  27. }
  28. int l,r;
  29. while(1){
  30. cin>>l>>r;
  31. cout<<query(l,r);
  32. }
  33. }

区间修改,单点求值

回到顶部

  1. #include <iostream>
  2. #define MX 500010
  3. #define lowbit(x) (x&(-x))
  4. using namespace std;
  5. int n,m,a[1000],c[1000];
  6. void add(int x,int k){
  7. for(;x<=n;x+=lowbit(x)){
  8. c[x]+=k;
  9. };
  10. }
  11. int sum(int x){
  12. int ans=0;
  13. for(x;x>=1;x-=lowbit(x)){
  14. ans+=c[x];
  15. }
  16. return ans;
  17. }
  18. int main(){
  19. cin>>n>>m;
  20. for(int i=1;i<=n;i++){
  21. cin>>a[i];
  22. }
  23. int q,w,e;
  24. for(int i=1;i<=m;i++){
  25. cin>>q;
  26. if(q==1){
  27. cin>>q>>w>>e;
  28. add(q,e);
  29. add(w+1,-e);
  30. }else{
  31. cin>>q;
  32. cout<<a[q]+sum(q)<<endl;
  33. }
  34. }
  35. }

高级应用:区间修改&区间求值

image_1citbhvdu1p131tviepd1vscr6t1p.png-24.2kB
如图,上面是线段树,下面是树状数组。
在区间加法和查询明显代码量以及时空效率都优于线段树。
当然如果要支持最大最小什么的可能只能用线段树了。

  1. #include <iostream>
  2. #define lowbit(x) (x&(-x))
  3. #define MX 100010
  4. #define LL long long
  5. using namespace std;
  6. LL n,m,q,c1[MX],c2[MX],a[MX];
  7. void add(LL *r,LL x,LL k){//采用LL *r传递每次要修改的数组
  8. for(;x<=n;x+=lowbit(x)){
  9. r[x]+=k;
  10. }
  11. }
  12. LL sum(LL *r,LL x){
  13. LL ans=0;
  14. for(;x>=1;x-=lowbit(x)){
  15. ans+=r[x];
  16. }
  17. return ans;
  18. }
  19. int main()
  20. {
  21. LL sum1,sum2;
  22. cin>>n>>m;
  23. for(int i=1;i<=n;i++){
  24. cin>>a[i];
  25. add(c1,i,a[i]-a[i-1]);
  26. add(c2,i,(i-1)*(a[i]-a[i-1]));
  27. }
  28. int q,l,r,k;
  29. for(int i=1;i<=m;i++){
  30. cin>>q;
  31. if(q==1){
  32. cin>>l>>r>>k;
  33. add(c1,l,k);
  34. add(c1,r+1,-k);
  35. add(c2,l,(l-1)*k);
  36. add(c2,r+1,-r*k);
  37. }else{
  38. cin>>l>>r;
  39. sum1=(l-1)*sum(c1,l-1)-sum(c2,l-1);
  40. sum2=r*sum(c1,r)-sum(c2,r);
  41. cout<<(sum2-sum1)<<endl;
  42. }
  43. }
  44. return 0;
  45. }

二维树状数组

等待填坑
回到顶部

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注