P3374 【模板】树状数组 1 题解

P3374 【模板】树状数组 1 题解

简化题意

我们有一个长度为 \(n\) 的数组,现在要对其进行 \(m\) 次以下两种操作:

  • 将一个数加上 \(x\)
  • 求出某个区间每一个数的和。

解题思路

这里,我们发现数据范围很大,直接暴力会超时。而如果采用前缀和,那么依然要进行值的修改,也不可取。
因此,我们要采用新的算法。
这里,引入树状数组。

树状数组算法利用了二进制的思想,这里我用一个例子帮助大家理解:

数字 \(1\) \(2\) \(3\) \(4\) \(5\) \(6\) \(7\) \(8\)
二进制表达 \(0001_{(2)}\) \(0010_{(2)}\) \(0011_{(2)}\) \(0100_{(2)}\) \(0101_{(2)}\) \(0110_{(2)}\) \(0111_{(2)}\) \(1000_{(2)}\)

如果我们要算 \(1 \sim 7\) 的和,怎么进行呢?
我们要创建一个数组 t,其中 \(t_i\) 代表数 \(x\) 到数 \(i\) 的和。这里的数 \(x\) 是什么呢?
借助上面的表格,我们指定 \(x\)\(i\) 的二进制表示最低位为 \(1\) 时,\(x\) 的此位为 \(0\),且其他数位相同的值。
这个很难理解。我们看几个例子,比如 \(t_2\) 存储的就是 \(0 \sim 2\) 的和(\(\textcolor{red}{0}0_{(2)} \sim \textcolor{red}{1}0_{(2)}\));\(t_3\) 存储的就是 \(2 \sim 3\) 的和(\(1\textcolor{red}{0}_{(2)} \sim 1\textcolor{red}{1}_{(2)}\));\(t_6\) 存储的就是 \(4 \sim 6\) 的和(\(1\textcolor{red}{0}0_{(2)} \sim 1\textcolor{red}{1}0_{(2)}\))。
这个操作的代码实现并不难,但是要是看不懂的就难以理解。我们对于一个需要更新的数给定的下标 \(i\),不断执行 \(i += i \land (-i)\) 即可得出每个需要的数组了。比如我们经过操作,更新 \(t_1\),会同步更新 \(t_2\)\(t_4\)\(t_8\)。原理就是这个操作每次更新了 \(i\) 的需要的位置(如上),使其由 \(0\) 变为 \(1\),即达到了上述的意义。
程序实现:

void add(int pos, int x)//区间更新 
{
	while(pos <= n)
	{
		t[pos] += x;
		pos += pos & -pos;//得到最低位 
	}
} 

而区间求和又怎么实现呢?很简单,把刚才的区间更新操作反过来执行就行了。我们拿到一个数,就把它不断的最低位若为 \(1\),就去除再求和。具体操作看下面代码吧。
程序实现:

int sum(int pos)//区间求和 
{
	int s = 0;
	while(pos)
	{
		s += t[pos];
		pos -= pos & -pos;
	}
	return s;
}

这样,我们就可以显著降低操作所需时间了。

这篇文章写的比较仓促,主要是记录自己的学习经历。可能有表达不清,请见谅。

代码部分

#include <bits/stdc++.h>
using namespace std;

int n, m, t[500010];
void add(int pos, int x)//区间更新 
{
	while(pos <= n)
	{
		t[pos] += x;
		pos += pos & -pos;//得到最低位 
	}
}
int sum(int pos)//区间求和 
{
	int s = 0;
	while(pos)
	{
		s += t[pos];
		pos -= pos & -pos;
	}
	return s;
}
void solve()
{
	int type, a, b;
	cin >> n >> m;
	for(int i = 1;i <= n;i ++)
	{
		scanf("%d", &a);
		add(i, a);	
	}
	for(int i = 1;i <= m;i ++)
	{
		scanf("%d %d %d", &type, &a, &b);
		if(type == 2)
			printf("%d\n", sum(b) - sum(a - 1));
		else
			add(a, b); 
	}
}

int main()
{
	solve(); 
	return 0;
}

posted on 2026-07-05 23:04  Leo_29  阅读(3)  评论(0)    收藏  举报

导航