数状数组解析 代码模板

本文介绍了树状数组在高效计算区间和、单点修改及区间修改场景中的重要性,通过Lowbit函数和示例演示如何构造和操作树状数组。此外,还涵盖了差分数组的应用,以及如何利用树状数组解决单点查询和区间查询问题。
摘要由CSDN通过智能技术生成

对文档提及的不够清楚的,可以结合文章末尾给出的视频链接学习

1.为什么需要树状数组

问题 1.假如给你一个数组 A[1] …A[m], 现在要求对数组部分区间的求.

问题 2. 假如给你一个数组 A[1] …A[m], 现在要求对数组部分区间的每一个元素 +k .

问题3. 假如给你一个数组 A[1] …A[m], 现在要求对数组某一区间进行求,也要对某一区间的元素 +k.

上面三个问题,可以进行通过遍历区间的每一个元素来求解,但是如果数据大,就会极大的减低代码运行的效率

为什么需要树状数组, 数组可以提高普通数组进行 区间查询 , 区间修改的效率

2. 什么是树状数组

树状数组是为了解决数据压缩里的累积频率的计算问题的一种数据模型,现多用于高效计算数列的前缀和,区间和。

三大作用: (高效进行)

  1. 单点修改, 区间查询
  2. 单间查询,区间修改
  3. 区间修改,区间查询

3. 学习

3.1 前置知识

(学习树状数组前,需要了解)
Lowbit 函数 :
定义一个Lowbit函数,返回参数转为二进制后,最后一个1的位置所代表的数值.

例如:

  • Lowbit(10) (10的二进制是 1010)的返回值将是2;
  • Lowbit(12) (12的二进制是 1100)返回4;
  • Lowbit(8) (1000)返回8。

程序上,(x&(-x))表明了最后一位1的值,

public static int lowbit(x){
	return x&(-x)
}

所以看到 x&(-x) 就应该想到lowbit,也就是x二进制最后一个1所代表的数.

3.2 树状数组(长什么样)

现在一个数组a[8] ,转换为树状数组t[8].

  • t[1] = a[1];
  • t[2] = a[1] + a[2];
  • t[3] = a[3];
  • t[4] = a[1] + a[2] + a[3] + a[4];

通过观察结论 t[x]的父节点 t[x + lowbit(x)] ; (前人总结的经验,没必要纠结我怎么就没想到呢)
t[1]的父节点 t [1 + lowbit(1)] = t[2]
t[4]的父节点 t [4 + lowbit(4)] = t[8]
树状数组

3.3单点修改, 区间查询

单点修改: 因为树状数组单位元素的值代表的部分前缀和.
例如 如果要在a[3] + 3; 那么就要在 t[3] , t[4] ,t[8] 分别加上 3

 public static void add(i, k){
	for( ; i<= t.length(); t += i&(-t) ){  // 下一个元素加上父节点
		t[x] +=k;
	}
}

前i项和 : 例如 t[5]的前 5项和 为 t[4] + t[5] , 要不断求出前项进行累加

	public static int ask(int x){
		int ans = 0;
		for( ; x>0; x-= x&(-x)){
	 		ans += t[x];
	 	}
	 	return ans;
	}	

**区间查询 ** : 求 l … r 项的和 ,为 前 r 项和 - 前 l-1 项的和.

	int n = ask(l) - ask(r-1);

3.4单间查询,区间修改

3.4.1 差分数组

学习1
学习2
因为其他博主已经写得很好了,我就不复述了,可以自行参考文章阅读.

3.4.2

利用差分数组的思想,树状数组t[n],保存也是差分数组 .
t [i] = (a[i] - a[i - 1 ]).

区间修改 :

 public static void add(i, k){
	for( ; i<= t.length(); t += i&(-t) ){  // 下一个元素加上父节点
		t[x] +=k;
	}
}


public static void change(int l, int r , int k){
	add(l,k);
	add(r+1,-k);
}

单点查询 : a[x] + ask[i] ; 相当 x + x的增量

	public static int ask(int x){
		int ans = 0;
		for( ; x>0; x-= x&(-x)){
	 		ans += t[x];
	 	}
	 	return ans;
	}

	public static int change(int i){
		return a[i] + ask[i]; 
	}

3.5区间修改,区间查询 (暂时跳过)

还没想好怎么写比较好 , (手动狗头保命 )

Ps: 参考资料

视频链接 :bilibili
博客链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值