zoukankan      html  css  js  c++  java
  • 树状数组

    看到树状数组后觉得这个数据结构很优美,比较有意思,虽然很多时候线段树能做,但树状数组内存消耗更小,思想也很有意思,就想记录一下

     看上去是比较漂亮的,A[] 是序列的实际数值, C[] 记录的是某一段A[]的和,例如 C[4]就是 sun(1--4)。

    先介绍个很关键的函数:int lowbit(int x){return x&(-x);} 这个可以返回二进制数 x 中最低位的 1 还是 1 ,其余都为 0 的数,比如对于 1000(8的二进制) 1000=100+lowbit(100)=110+lowbit(110)=111+lowbit(111);

    其实 C[i] 有很多性质:

    1,将 i 化为二进制,比如 i = 6 = 110 那么 lowbit(6) = 2 ,代表 C[6] 记录了 2 个数的和, lowbit(7)=1 ,所以 C[7] 记录的 1 个数的和,所以查询时 i-lowbit(i) 会到 C[i] 恰好没覆盖到的地方

    2,C[i]的父节点是 C[i+lowbit(i)],也就是说,i+lowbit(i) 是记录了 i 记录的前缀和的,所以更新时要不断向父节点更新。

    看懂了这些再看看代码,很容易理解了

     求区间和O(log n),便于单点更新,区间查询:

     1 #include <iostream>
     2 #include <stdio.h>
     3 #include <string.h>
     4 
     5 using namespace std;
     6 #define MAXN 1000
     7 
     8 int n;
     9 int A[MAXN];
    10 int C[MAXN];
    11 
    12 int lowbit(int x)
    13 {
    14     return x&(-x);
    15 }
    16 
    17 void update(int x,int add) //A[x]增减
    18 {
    19     while (x<=n)
    20     {
    21         C[x]+=add;
    22         x+=lowbit(x);
    23     }
    24 }
    25 
    26 void new_tree(int n)   //建树,直接利用update
    27 {
    28     memset(C,0,sizeof(C));
    29     for (int i=1;i<=n;i++)
    30         update(i,A[i]);
    31 }
    32 
    33 int getsum(int x)//[1--x]的和
    34 {
    35     int sum=0;
    36     while(x>0)
    37     {
    38         sum+=C[x];
    39         x -= lowbit(x); //性质1
    40     }
    41     return sum;
    42 }
    43 
    44 int main()
    45 {
    46     scanf("%d",&n);
    47     for (int i=1;i<=n;i++)
    48         scanf("%d",&A[i]);
    49     new_tree(n);
    50 
    51     int l,r;
    52     scanf("%d %d",&l,&r);
    53     printf("%d
    ",getsum(r)-getsum(l-1)); //l--r 的和
    54 
    55     return 0;
    56 }
    View Code

     虽然用前缀和求区间和是O(1),但是不便更新

    树状数组还可以很方便的做区间更新,单点查询,更新时 update(L,v),update(R+1,-v) ,查询为 get_sum(i), 即可,还是因为树状数组保存的是前缀和的原因

     还可以升级到多维的,很厉害

  • 相关阅读:
    (Java实现) 洛谷 P1603 斯诺登的密码
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1036 选数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1012 拼数
    (Java实现) 洛谷 P1028 数的计算
    (Java实现) 洛谷 P1028 数的计算
    (Java实现) 洛谷 P1553 数字反转(升级版)
    8.4 确定两个日期之间的月份数或年数
    (Java实现) 洛谷 P1553 数字反转(升级版)
  • 原文地址:https://www.cnblogs.com/haoabcd2010/p/6657393.html
Copyright © 2011-2022 走看看