一维树状数组
长度为nnn的序列: a1,a2,⋯ ,ana_1,a_2,\cdots,a_na1,a2,⋯,an
一阶差分与前缀和
一阶差分数组: di=ai−ai−1(a0=0)d_i=a_i-a_{i-1}\qquad(a_0=0)di=ai−ai−1(a0=0)
考虑序列aaa第mmm项:
am=∑i=1mdia_m=\sum\limits_{i=1}^m d_iam=i=1∑mdi
考虑序列aaa前mmm项和:
∑i=1mai=∑i=1m∑j=1idj=∑i=1m(m+1−i)⋅di=(m+1)∑i=1mdi−∑i=1mi⋅di\sum\limits_{i=1}^ma_i=\sum\limits_{i=1}^m\sum\limits_{j=1}^id_j=\sum\limits_{i=1}^m(m+1-i)\cdotp d_i=(m+1)\sum\limits\limits_{i=1}^md_i-\sum\limits_{i=1}^mi\cdotp d_ii=1∑mai=i=1∑mj=1∑idj=i=1∑m(m+1−i)⋅di=(m+1)i=1∑mdi−i=1∑mi⋅di
//区间加常数
for(int i=l;i<=r;++i)
a[i]+=v;
//查询区间和
for(int i=l;i<=r;++i)
sum+=a[i];
return sum;
树状数组优化上面的代码, 复杂度: O(nlogn)O(n\log n)O(nlogn)
struct BinaryIndexTree
{
static const int __=1e5+5;
typedef ll type;
int n;type a[2][__];
void add(int x,type v)
{
for(int i=x;i<=n;i+=i&-i)
{
a[0][i]+=v;
a[1][i]+=x*v;
}
}
void add(int l,int r,type v)
{
if(l>r)return;
add(l,v),add(r+1,-v);
}
type sum(int x)
{
type b[2]={0};
for(int i=x;i;i-=i&-i)
{
b[0]+=a[0][i];
b[1]+=a[1][i];
}
return (x+1)*b[0]-b[1];
}
type sum(int l,int r)
{
if(l>r)return 0;
return sum(r)-sum(l-1);
}
}B;
二阶差分与前缀和
二阶差分数组: ei=di−di−1=ai−2⋅ai−1+ai−2(a−1=a0=0)e_i=d_i-d_{i-1}=a_i-2\cdotp a_{i-1}+a_{i-2}\qquad(a_{-1}=a_0=0)ei=di−di−1=ai−2⋅ai−1+ai−2(a−1=a0=0)
考虑序列aaa第mmm项:
am=∑i=1mdi=∑i=1m∑j=1iej=(m+1)∑i=1mei−∑i=1mi⋅eia_m=\sum\limits_{i=1}^m d_i=\sum\limits_{i=1}^m\sum\limits_{j=1}^ie_j=(m+1)\sum\limits\limits_{i=1}^me_i-\sum\limits_{i=1}^mi\cdotp e_iam=i=1∑mdi=i=1∑mj=1∑iej=(m+1)i=1∑mei−i=1∑mi⋅ei
考虑序列aaa前mmm项和:
∑i=1mai=∑i=1m((i+1)∑j=1iej−∑j=1ij⋅ej)=(∑i=1mei∑j=i+1m+1j)−(∑i=1mei⋅((m+1−i)⋅i))=(∑i=1mei⋅(m+2+i)⋅(m+1−i)2)−(∑i=1mei⋅((m+1−i)⋅i))=∑i=1mei⋅(m+2−i)⋅(m+1−i)2=∑i=1mei⋅(m2+3m+2)−(2m+3)⋅i+i22=(m+1)(m+2)2∑i=1mei−2m+32∑i=1mi⋅ei+12∑i=1mi2⋅ei\begin{aligned} \sum\limits_{i=1}^ma_i&=\sum\limits_{i=1}^m\Big((i+1)\sum\limits\limits_{j=1}^ie_j-\sum\limits_{j=1}^ij\cdotp e_j\Big)\\ &=\Big(\sum\limits_{i=1}^me_i\sum\limits_{j=i+1}^{m+1}j\Big)-\Big(\sum\limits_{i=1}^me_i\cdot\big((m+1-i)\cdotp i\big)\Big)\\ &=\Big(\sum\limits_{i=1}^me_i\cdot\frac{(m+2+i)\cdotp(m+1-i)}{2}\Big)-\Big(\sum\limits_{i=1}^me_i\cdot\big((m+1-i)\cdotp i\big)\Big)\\ &=\sum\limits_{i=1}^me_i\cdot\frac{(m+2-i)\cdotp(m+1-i)}{2}\\ &=\sum\limits_{i=1}^me_i\cdot\frac{(m^2+3m+2)-(2m+3)\cdotp i+i^2}{2}\\ &=\frac{(m+1)(m+2)}{2}\sum\limits_{i=1}^me_i-\frac{2m+3}{2}\sum\limits_{i=1}^mi\cdotp e_i+\frac{1}{2}\sum\limits_{i=1}^mi^2\cdotp e_i \end{aligned}i=1∑mai=i=1∑m((i+1)j=1∑iej−j=1∑ij⋅ej)=(i=1∑meij=i+1∑m+1j)−(i=1∑mei⋅((m+1−i)⋅i))=(i=1∑mei⋅2(m+2+i)⋅(m+1−i))−(i=1∑mei⋅((m+1−i)⋅i))=i=1∑mei⋅2(m+2−i)⋅(m+1−i)=i=1∑mei⋅2(m2+3m+2)−(2m+3)⋅i+i2=2(m+1)(m+2)i=1∑mei−22m+3i=1∑mi⋅ei+21i=1∑mi2⋅ei
//区间加一次函数
for(int i=l;i<=r;++i)
a[i]+=(i-l)*k+b;
//查询区间和
for(int i=l;i<=r;++i)
sum+=a[i];
return sum;
树状数组优化以上代码, 复杂度: O(nlogn)O(n\log n)O(nlogn)
struct BinaryIndexTree
{
static const int __=1e5+5;
typedef ll type;
int n;type a[3][__];
void add(int x,type v)
{
for(int i=x;i<=n;i+=i&-i)
{
a[0][i]+=v;
a[1][i]+=x*v;
a[2][i]+=x*x*v;
}
}
//a[i]+=b+k*(i-l)
void add(int l,int r,type k,type b)
{
if(l>r)return;
add(l,b);
add(l+1,k-b);
add(r+1,-b-(r-l+1)*k);
add(r+2,b+(r-l)*k);
}
type sum(int x)
{
type b[3]={0};
for(int i=x;i;i-=i&-i)
{
b[0]+=a[0][i];
b[1]+=a[1][i];
b[2]+=a[2][i];
}
return ((x+1)*(x+2)*b[0]-(2*x+3)*b[1]+b[2])/2;
}
type sum(int l,int r)
{
if(l>r)return 0;
return sum(r)-sum(l-1);
}
}B;
kkk阶差分与前缀和
不难看出: 在维护原数组aia_iai的kkk阶差分数组bib_ibi时, aia_iai的前mmm项和都是如下几个相同形式的部分求和
∑f(m)⋅∑i=1mic⋅bi(f(x)\sum f(m)\cdotp\sum\limits_{i=1}^m i^c\cdotp b_i\qquad\big(f(x)∑f(m)⋅i=1∑mic⋅bi(f(x)是关于xxx的多项式)\big))
考虑一个部分的前mmm项和:
∑i=1mf(i)∑j=1ijc⋅bj=∑i=1mic⋅bi∑j=imf(j)=∑i=1mic⋅bi⋅(∑j=1mf(j)−∑j=1i−1f(j))=∑i=1mic⋅bi⋅(g(m)−g(i−1))(g(n)=∑i=1nf(i))\begin{aligned} \sum\limits_{i=1}^mf(i)\sum\limits_{j=1}^i j^c\cdotp b_j&=\sum\limits_{i=1}^mi^c\cdotp b_i\sum\limits_{j=i}^m f(j)=\sum\limits_{i=1}^mi^c\cdot b_i\cdotp\Big(\sum\limits_{j=1}^m f(j)-\sum\limits_{j=1}^{i-1} f(j)\Big)\\ &=\sum\limits_{i=1}^mi^c\cdot b_i\cdotp\big(g(m)-g(i-1)\big)\qquad\Big(g(n)=\sum\limits_{i=1}^n f(i)\Big) \end{aligned}i=1∑mf(i)j=1∑ijc⋅bj=i=1∑mic⋅bij=i∑mf(j)=i=1∑mic⋅bi⋅(j=1∑mf(j)−j=1∑i−1f(j))=i=1∑mic⋅bi⋅(g(m)−g(i−1))(g(n)=i=1∑nf(i))
运用上述方法不难求得三阶差分数组fif_ifi与前缀和的关系
∑i=1mai=(m+1)(m+2)(m+3)6∑i=1mfi−3m2+12m+116∑i=1mi⋅fi+m+22∑i=1mi2⋅fi−16∑i=1mi3⋅fi\sum\limits_{i=1}^ma_i=\frac{(m+1)(m+2)(m+3)}{6}\sum\limits_{i=1}^m f_i-\frac{3m^2+12m+11}{6}\sum\limits_{i=1}^m i\cdotp f_i+\frac{m+2}{2}\sum\limits_{i=1}^m i^2\cdotp f_i-\frac{1}{6}\sum\limits_{i=1}^m i^3\cdotp f_ii=1∑mai=6(m+1)(m+2)(m+3)i=1∑mfi−63m2+12m+11i=1∑mi⋅fi+2m+2i=1∑mi2⋅fi−61i=1∑mi3⋅fi
//区间加二次函数
for(int i=l;i<=r;++i)
a[i]+=(i-l)*(i-l)*x+(i-l)*y+z;
//查询区间和
for(int i=l;i<=r;++i)
sum+=a[i];
return sum;
树状数组优化以上代码, 复杂度: O(nlogn)O(n\log n)O(nlogn)
struct BinaryIndexTree
{
static const int __=1e5+5;
typedef ll type;
int n;type a[4][__];
void add(int x,type v)
{
for(int i=x;i<=n;i+=i&-i)
{
a[0][i]+=v;
a[1][i]+=x*v;
a[2][i]+=x*x*v;
a[3][i]+=x*x*x*v;
}
}
//a[i]+=x*(i-l)*(i-l)+y*(i-l)+z;
void add(int l,int r,type x,type y,type z)
{
if(l>r)return;
add(l,z);
add(l+1,x+y-2*z);
add(l+2,x-y+z);
type p=r-l+1,q=r-l;
add(r+1,-p*p*x-p*y-z);
add(r+2,(p*p+q*q-2)*x+(p+q)*y+2*z);
add(r+3,-q*q*x-q*y-z);
}
type sum(int x)
{
type b[4]={0};
for(int i=x;i;i-=i&-i)
{
b[0]+=a[0][i];
b[1]+=a[1][i];
b[2]+=a[2][i];
b[3]+=a[3][i];
}
return ((x+1)*(x+2)*(x+3)*b[0]-(3*x*x+12*x+11)*b[1]+(3*x+6)*b[2]-b[3])/6;
}
type sum(int l,int r)
{
if(l>r)return 0;
return sum(r)-sum(l-1);
}
}B;