差分与树状数组

一维树状数组

长度为 n n n的序列: a 1 , a 2 , ⋯   , a n a_1,a_2,\cdots,a_n a1,a2,,an

一阶差分与前缀和

一阶差分数组: d i = a i − a i − 1 ( a 0 = 0 ) d_i=a_i-a_{i-1}\qquad(a_0=0) di=aiai1(a0=0)

考虑序列 a a a m m m项:

a m = ∑ i = 1 m d i a_m=\sum\limits_{i=1}^m d_i am=i=1mdi

考虑序列 a a a m m m项和:

∑ i = 1 m a i = ∑ i = 1 m ∑ j = 1 i d j = ∑ i = 1 m ( m + 1 − i ) ⋅ d i = ( m + 1 ) ∑ i = 1 m d i − ∑ i = 1 m i ⋅ d i \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_i i=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 ( n log ⁡ 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;
二阶差分与前缀和

二阶差分数组: e i = d i − d i − 1 = a i − 2 ⋅ a i − 1 + a i − 2 ( a − 1 = a 0 = 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)

考虑序列 a a a m m m项:

a m = ∑ i = 1 m d i = ∑ i = 1 m ∑ j = 1 i e j = ( m + 1 ) ∑ i = 1 m e i − ∑ i = 1 m i ⋅ e i a_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_i am=i=1mdi=i=1mj=1iej=(m+1)i=1meii=1miei

考虑序列 a a a m m m项和:

∑ i = 1 m a i = ∑ i = 1 m ( ( i + 1 ) ∑ j = 1 i e j − ∑ j = 1 i j ⋅ e j ) = ( ∑ i = 1 m e i ∑ j = i + 1 m + 1 j ) − ( ∑ i = 1 m e i ⋅ ( ( m + 1 − i ) ⋅ i ) ) = ( ∑ i = 1 m e i ⋅ ( m + 2 + i ) ⋅ ( m + 1 − i ) 2 ) − ( ∑ i = 1 m e i ⋅ ( ( m + 1 − i ) ⋅ i ) ) = ∑ i = 1 m e i ⋅ ( m + 2 − i ) ⋅ ( m + 1 − i ) 2 = ∑ i = 1 m e i ⋅ ( m 2 + 3 m + 2 ) − ( 2 m + 3 ) ⋅ i + i 2 2 = ( m + 1 ) ( m + 2 ) 2 ∑ i = 1 m e i − 2 m + 3 2 ∑ i = 1 m i ⋅ e i + 1 2 ∑ i = 1 m i 2 ⋅ e i \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 ( n log ⁡ 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;
k k k阶差分与前缀和

不难看出: 在维护原数组 a i a_i ai k k k阶差分数组 b i b_i bi时, a i a_i ai的前 m m m项和都是如下几个相同形式的部分求和

∑ f ( m ) ⋅ ∑ i = 1 m i c ⋅ b i ( 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)是关于 x x x的多项式 ) \big) )

考虑一个部分的前 m m m项和:

∑ i = 1 m f ( i ) ∑ j = 1 i j c ⋅ b j = ∑ i = 1 m i c ⋅ b i ∑ j = i m f ( j ) = ∑ i = 1 m i c ⋅ b i ⋅ ( ∑ j = 1 m f ( j ) − ∑ j = 1 i − 1 f ( j ) ) = ∑ i = 1 m i c ⋅ b i ⋅ ( g ( m ) − g ( i − 1 ) ) ( g ( n ) = ∑ i = 1 n f ( 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))

运用上述方法不难求得三阶差分数组 f i f_i fi与前缀和的关系

∑ i = 1 m a i = ( m + 1 ) ( m + 2 ) ( m + 3 ) 6 ∑ i = 1 m f i − 3 m 2 + 12 m + 11 6 ∑ i = 1 m i ⋅ f i + m + 2 2 ∑ i = 1 m i 2 ⋅ f i − 1 6 ∑ i = 1 m i 3 ⋅ f i \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_i i=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 ( n log ⁡ 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;
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值