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

116 阅读2分钟

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

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

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

  • 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;
}