树状数组基础

本篇博客主要讲解树状数组的基础应用

1、单点修改与区间查询

2、区间修改与单点查询

树状数组的用处及优势

相比于线段树其扩展性较弱,但代码短容易实现,一般来说以上两种情况用树状数组解决,区间的修改与查询用线段树更加方便。

树状数组的结构

前置知识:

位运算 lowbit 

观察下图(图片出自一篇好文link

 图中c[i]表示以 i 为根的树的叶子节点之和(就是树状数组)

观察树的每一个分支,乍一看没有什么关系,但我们将其转化为二进制

 

横竖观察

你会发现同根同层的数字从右往左依次减去自己的lowbit()

如4=6-lowbit(6)   2=3-lowbit(3)

而一个节点其父节点的值是当前节点+lowbit(它自己)

如 8=4+lowbit(4)  4=3+lowbit(4)

这两个发现对于树状数组的维护与查询具有重要作用

树状数组的实现

单点修改 区间查询

1、单点修改

在修改某个节点时,我们需要修改所有包括该节点的位置。

根据上述结论,一个节点的祖先节点就是包括它的节点,我们只需要不断向上遍历修改。

向上遍历就可以用加lowbit()实现

void dd(int x,int k)//在节点x加k
{
	for(int i=x;i<=n;i+=lowbit(i)) c[i]+=k;
}

2、区间查询

首先试求1~x之和

设x=7,如图

 仔细观察7 6 4 三个数,发现从右到左又是递减lowbit()的关系,多举几个例子会发现这并不是偶然

有了这个发现,前x个数的求和就可以轻松完成

而查询l~r的数字之和

此时运用前缀和思想,用1~r之和减去1~l之和得到答案

int search(int l,int r)
{
    int ans=0;
	for(int i=r;i;i-=lowbit(i)) ans+=c[i];
	for(int i=l-1;i;i-=lowbit(i)) ans-=c[i];
    return ans;
}

区间修改 单点查询

对于区间类操作,不难想到使用差分,所以此时将树状数组用来维护原数组的差分数组

对于区间修改,我们只需要对差分数组进行操作即可,例如对区间[l,r]+k,那么我们只需要更新差分数组add(l,k),add(r+1,-k)

代码基本没有差别

void qj(int x,int k){
	for(int i=x;i<=n;i+=lowbit(i)){
		c[i]+=k;
	}
}
qj(l,k);
qj(r+1,k);

单点查询,根据差分数组性质,求出树状数组前缀和即可

void search(int y)
{
	for(int i=y;i;i-=lowbit(i)) ans+=c[i];
}

区间修改与区间查询

区间类的操作对于树状数组来说更加繁琐,这种情况一般运用线段树,在这里不赘述

本蒟蒻会尽量学会线段树o

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值