树状数组

树状数组(求前缀和的利器)已同步

标签:ACM


一维树状数组

//bt[i]和bt[j]管辖的区间之间要么是完全包含的,要么是不重叠的

//b[i]覆盖的长度是lowbit(i)

int bt[maxn];//树状数组,下标必须从1开始,不然lowbit(0)=0会出现死循环

#define lowbit(i) ((x)&(-x))

void update(int x,int v)//第x个数加上v,沿着 右上 的路径前进的,不断定位最右边1的左边0的过程
{
    for(int i=x;i<=n;i+=lowbit(i))//最近的包含i的区间是i+lowbit(i),
        bt[i]+=v;
}

//注意点:求第4到第9个数时,不能直接将i>0改为i>=4(会算进多余的数,性质),应该getsum(9)-getsum(4-1)

int getsum(int x)//前x个数之和,沿着左上前进,不断把x的最右边的1置0的过程
{
    int sum=0;
    for(int i=x;i>0;i-=lowbit(i))
        sum+=bt[i];
    return sum;
}

二维及以上的树状数组

//如果单独把二维中的第一个维度拿出来A[1][m] + A[2][m] = C[2][m],A[3][m] = C[3][m],
//是不是也和一维的数组一样,所以二维数组的规律就是,不管是横坐标还是纵坐标,将他们单独拿出来,他们都符合x += lowbit(x),属于它的父亲节点

int bt[maxn][maxn];//树状数组,下标必须从1开始,不然lowbit(0)=0会出现死循环

#define lowbit(i) ((x)&(-x))

void update(int x,int y,int v)//第x个数加上v,沿着 右上 的路径前进的,不断定位最右边1的左边0的过程
{
    for(int i=x;i<=n;i+=lowbit(i))//最近的包含i的区间是i+lowbit(i),
        for(int j=y;j<=n;j+=lowbit(j))
            bt[i][j]+=v;
}


//注意点:求第4到第9个数时,不能直接将i>0改为i>=4(会算进多余的数,性质),应该getsum(9)-getsum(4-1)

int getsum(int x,int y)//前x个数之和,沿着左上前进,不断把x的最右边的1置0的过程
{
    int sum=0;
    for(int i=x;i>0;i-=lowbit(i))
        for(int j=y;j>0;j-=lowbit(j))
            sum+=bt[i][j];
    return sum;
}

区间更新,单点查询

//跟区间查询,单点更新正好相反
int bt[maxn];
int n;
int update(int x,int v){//前x个整数都加上v
    for(int i=x;i>0;i-=lowbit(i))
        c[i]+=v;
}

int getnum(int x){//返回第i个数的值
   int ans=0;
   for(int i=x;i<=n;i+=lowbit(i))
       ans+=bt[i];
   return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值