什么是差分?
7 8 6 5 8 18 20 35 //原数组
7 1 -2 -1 3 10 2 15 //差分数组
差分数组的前缀sum[i]即原数组的a[i]
我们构建两个树状数组
sum1:7 1 -2 -1 3 10 2 15
sum2:7 2 -6 -4 15 60 14 120
第二个数组是sum1[i]*i
那么我们怎么算原数组的前缀和呢??
例如求前4个数的和7+8+6+5=26
=5*(7+1-2-1)-(7+2-6-4)=26
即有公式(求原数组前缀和)
sum(i)=(i+1)(sum1[1]+sum1[2]+…+sum1[i])-(sum2[1]+sum2[2]+…+sum2[i])
即(i+1)*差分数组前缀和(i)-差分数组乘坐标数组(即sum2)的前缀和
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <map>
#include <math.h>
#include <cstring>
#include <string.h>
#include <queue>
#include<list>
#include<cstdarg>
#define ll long long
using namespace std;
ll c[200010];
ll a[200010]; ll n, m, k;
inline ll lowbit(ll x) { return x & (-x); }
void add(ll x, ll d)
{
for (ll i = x; i <= n; i += lowbit(i))
{
c[i] += d;
a[i] += x * d;
}
}
ll sum(ll x)
{
ll s = 0;
for (ll i = x; i; i -= lowbit(i))
{
s += (x + 1) * c[i] - a[i];
}
return s;
}
int main()
{
cin >> n >> m;
ll x;
ll last = 0;
for (ll i = 1; i <= n; i++)
{
cin >> x;
add(i, x - last);
last = x;
}
ll main_ = 0;
while (m--)
{
ll op;
cin >> op;
if (op == 1)
{
ll t1, t2, t3;
cin >> t1 >> t2 >> t3;
add(t1, t3);
add(t2 + 1, -t3);
}
if (op == 2)
{
ll t3;
cin >> t3;
main_ += t3;
}
if (op == 3)
{
ll t3;
cin >> t3;
main_ -= t3;
}
if (op == 4)
{
ll t1, t2;
cin >> t1 >> t2;
if (t1 == 1)
{
cout << sum(t2) - sum(t1 - 1) + main_ << '\n';
}
else cout << sum(t2) - sum(t1 - 1) << '\n';
}
if (op == 5)
{
cout << sum(1) + main_ << '\n';
}
}
}