洛谷 P3372 线段树1 (树状数组区间修改区间查询)

题面

给一个数列,需要满足以下两种操作:
①区间加x
②区间求和

数列规模N<=100000,操作数M<=100000

分析

树状数组基础:logN内区间求和,logN内单点修改
让树状数组维护差分数组,能做到单点求值, 区间修改。
让树状数组可以同时在区间查询+区间修改是对维护量进行变更。

从队友那里问到了如下等式
设di是差分数组,ai是原数组,即
a 1 = d 1 a1=d1
a 2 = d 1 + d 2 a2=d1+d2
a 3 = d 1 + d 2 + d 3 a3=d1+d2+d3

a n = d 1 + d 2 + d 3.. + d n an=d1+d2+d3..+dn
有如下关系
i = 1 n a i = ( n + 1 ) a n i = 1 n i c i \sum_{i=1}^{n}a_{i}=(n+1)a_{n}-\sum_{i=1}^{n}i*c_{i}
可以自己验证一下

有了这个之后,可知要维护两个树状数组:
①单纯的差分数组,从而求 a n a_{n}
②数组 i c i i*c_{i} ,从而能求出后面项的 \sum

代码

#include "cstdlib"
#include "iostream"
#include<iostream>
#include<vector>
#include<stack>
#include<algorithm>
using namespace std;
#define lowbit(x) (x&(-x))//lowbit操作:x&(-x),取到最低位的1及其后的0
class Binary_Indexed_Tree {
private:
	const static int MAXN = 100005;
	long long C[MAXN];
public:
	int N;//一共1~n
	void add(int p, long long v)//单点加
	{
		while (p <= N)
		{
			C[p] += v;
			p += lowbit(p);
		}
	}
	long long query(int p)//查询从1到p的前缀和
	{
		long long ans = 0;
		while (p)
		{
			ans += C[p];
			p -= lowbit(p);
		}
		return ans;
	}
}diff, idiff;//维护差分 和 i*差分di
class BIT_chunk {
public:
	void add(int l, int r, long long v)//[l,r]内加v,即改变两端的差分值(两个单点修改)
	{
		diff.add(l, v);
		idiff.add(l, l * v);
		if (r < diff.N) { diff.add(r + 1, -v); idiff.add(r + 1, -v * (r + 1)); }
	}
	long long query(int l, int r)//根据公式,对两个差分分别计算区间和
	{
		return (r + 1) * diff.query(r) - idiff.query(r) - l * diff.query(l - 1) + idiff.query(l - 1);
	}
	void create(int *A, int s,int n)//数组,起点,长度
	{
		diff.N = n;
		idiff.N = n;
		diff.add(1, A[s]);
		idiff.add(1, 1 * A[s]);
		for (int i = s+1,j=2; i <= n; i++,j++)
		{
			diff.add(i, A[i] - A[i - 1]);
			idiff.add(i, j * (A[i] - A[i - 1]));
		}
	}
}BIT;
int arr[100005];
int main()
{
	ios::sync_with_stdio(false);
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)cin >> arr[i];
	BIT.create(arr, 1, n);
	int op, k;
	long long x, y;
	for (int i = 0; i < m; i++)
	{
		cin >> op >> x >> y;
		if (op == 1) { cin >> k;BIT.add(x, y, k); }
		else { cout << BIT.query(x, y) << endl; }
	}
	return 0;
}



发布了32 篇原创文章 · 获赞 0 · 访问量 1182

猜你喜欢

转载自blog.csdn.net/engineoid/article/details/104225741