差分与树状数组

一维树状数组

长度为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=aiai1(a0=0)

考虑序列aaammm项:

am=∑i=1mdia_m=\sum\limits_{i=1}^m d_iam=i=1mdi

考虑序列aaammm项和:

∑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=1mai=i=1mj=1idj=i=1m(m+1i)di=(m+1)i=1mdii=1midi

//区间加常数
for(int i=l;i<=r;++i)
    a[i]+=v;
//查询区间和
for(int i=l;i<=r;++i)
    sum+=a[i];
return sum;

树状数组优化上面的代码, 复杂度: O(nlog⁡n)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=didi1=ai2ai1+ai2(a1=a0=0)

考虑序列aaammm项:

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=1mdi=i=1mj=1iej=(m+1)i=1meii=1miei

考虑序列aaammm项和:

∑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&amp;=\sum\limits_{i=1}^m\Big((i+1)\sum\limits\limits_{j=1}^ie_j-\sum\limits_{j=1}^ij\cdotp e_j\Big)\\ &amp;=\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)\\ &amp;=\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)\\ &amp;=\sum\limits_{i=1}^me_i\cdot\frac{(m+2-i)\cdotp(m+1-i)}{2}\\ &amp;=\sum\limits_{i=1}^me_i\cdot\frac{(m^2+3m+2)-(2m+3)\cdotp i+i^2}{2}\\ &amp;=\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=1mai=i=1m((i+1)j=1iejj=1ijej)=(i=1meij=i+1m+1j)(i=1mei((m+1i)i))=(i=1mei2(m+2+i)(m+1i))(i=1mei((m+1i)i))=i=1mei2(m+2i)(m+1i)=i=1mei2(m2+3m+2)(2m+3)i+i2=2(m+1)(m+2)i=1mei22m+3i=1miei+21i=1mi2ei

//区间加一次函数
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(nlog⁡n)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_iaikkk阶差分数组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=1micbi(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&amp;=\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)\\ &amp;=\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=1mf(i)j=1ijcbj=i=1micbij=imf(j)=i=1micbi(j=1mf(j)j=1i1f(j))=i=1micbi(g(m)g(i1))(g(n)=i=1nf(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=1mai=6(m+1)(m+2)(m+3)i=1mfi63m2+12m+11i=1mifi+2m+2i=1mi2fi61i=1mi3fi

//区间加二次函数
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(nlog⁡n)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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值