树状数组练习(区间修改,单点查询)Day03

前两天写的都是单点修改,区间查询的树状数组,今天来练习一下区间修改,单点查询的树状数组,本文适合学过单点修改,区间查询的朋友阅读。

单点修改,区间查询传送门

首先简单介绍一下区间修改,单点查询与之前单点修改,区间查询的区别。

  • tr[N]用来存储原数组的差分
  • lowbit函数,用来分层
int lowbit(int x)
{
    return x & -x;
}
  • 对某一点加一个数
void add(int x, int v)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i] += v;
}
  • 某一点变成另外一个数
void add(int x, int v)
{
    for(int i=x;i<=n;i+=lowbit(i)) tr[i] += v - tr[i];
    //tr[i] = tr[i] - tr[i] + v; 
}
  • 求前缀和
int sum(int x)
{
    int ans = 0;
    for(int i=x;i!=0;i-=lowbit(i)) ans += tr[i];
    return ans;
}

没错,你没有看错,这两种树状数组的基本函数并没有太大区别,区别在于,第二种的树状数组存的是差分而不是数本身。 为什么存差分呢?下面以这道题为例讲解。

模板题
P3368 【模板】树状数组 2

image.png

注意区别

在这里,我们的树状数组存的是差分!!!

原因如下:差分就是每两个数之间的差值,假设我们现在有原数据:a[1],a[2]...a[x]

那么原数据的差分相加就为:

(a[1]−0) + (a[2]−a[1]) + (a[3]−a[2]) + (a[4]−a[3]) +…+ (a[x]−a[x−1]) = a[x]

很巧妙的得到了a[x]

	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		add(i, a[i] - c);
		c = a[i];//差分
	}

还有就是修改区间,也是差分的性质。

    {
	cin >> x >> y >> z;
	add(x,z);
	add(y+1,-z);//差分的性质
    }
AC代码
int lowbit(int x)
{
	return x & -x;
}

void add(int x, int v)
{
	for (int i = x; i <= N; i += lowbit(i)) tr[i] += v;
}

int query(int x)
{
	int res = 0;
	for (int i = x; i != 0; i -= lowbit(i)) res += tr[i];
	return res;
}
signed main()
{

	int n, w, c = 0;
	cin >> n >> w;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		add(i, a[i] - c);
		c = a[i];//差分
	}

	while (w--)
	{
		int op,x,y,z;
		cin >> op;
		if (op == 1)
		{
			cin >> x >> y >> z;
			add(x,z);
			add(y+1,-z);//差分的性质
		}
		else
		{
			cin >> x;
			cout << query(x) << endl;
		}
	}
	return 0;
}

还有这道题,其实也是模板

P4939 Agent2

image.png

AC代码
const int N = 10000010;
int a[N],tr[N];

int lowbit(int x)
{
	return x & -x;
}

void add(int x, int v)
{
	for (int i = x; i <= N; i += lowbit(i)) tr[i] += v;
}

int query(int x)
{
	int res = 0;
	for (int i = x; i != 0; i -= lowbit(i)) res += tr[i];
	return res;
}
signed main()
{

	int n, w, c = 0;
	cin >> n >> w;


	while (w--)
	{
		int op, x, y;
		cin >> op;
		if (op == 0)
		{
			cin >> x >> y;
			add(x,1);
			add(y+1,-1);//差分的性质
		}
		else 
		{
			cin >> x;
			cout << query(x) << endl;
		}
	}
	return 0;
}
  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
树状数组(Fenwick Tree)是一种用于高效处理区间修改单点查询数据结构。下面我将介绍如何使用树状数组实现区间修改单点查询。 首先,我们需要定义树状数组数据结构树状数组由一个数组和一组操作组成,其中数组用于存储数据,操作用于更新和查询数组中的值。 下面是一个示例的树状数组实现: ```python class FenwickTree: def __init__(self, n): self.size = n self.tree = [0] * (n + 1) def update(self, idx, delta): while idx <= self.size: self.tree[idx] += delta idx += idx & -idx def query(self, idx): res = 0 while idx > 0: res += self.tree[idx] idx -= idx & -idx return res def range_update(self, l, r, delta): self.update(l, delta) self.update(r + 1, -delta) def point_query(self, idx): return self.query(idx) ``` 在上面的代码中,我们定义了一个FenwickTree类,通过构造函数`__init__`来初始化树状数组,并使用`size`来表示数组的大小。`tree`数组用于存储数据。`update`方法用于更新指定位置的值,`query`方法用于查询指定位置之前的求和结果。`range_update`方法用于对指定区间进行修改,`point_query`方法用于查询单个位置的值。 下面是一个示例的使用场景: ```python # 示例使用 n = 10 tree = FenwickTree(n) # 区间修改 [2, 6] 的值加 3 tree.range_update(2, 6, 3) # 查询位置 5 的值 value = tree.point_query(5) print(value) ``` 在上面的示例中,我们创建了一个大小为10的树状数组,并对区间[2, 6]的值进行了修改,将其加3。然后,我们查询了位置5的值,结果为3。 希望以上内容能够帮助到你实现树状数组区间修改单点查询。如果还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值