进阶版树状数组

时间:2022-07-25
本文章向大家介绍进阶版树状数组,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

我们都知道树状数组一般有两种形式

1.最为传统的版本,支持区间求和,单点修改

2.差分树状数组 支持区间修改,单点查询

而进阶版树状数组 可支持 区间求和,区间修改

其原理是:

设tree[i]=a[i]-a[i-1](差分),那么容易得到:

tree[1]+tree[2]+……+tree[i]=a[i]这个公式

维护tree数组即可以实现区间修改了。

接下来是区间查询的实现问题

我们已经推出了一个公式:

tree[1]+tree[2]+……tree[i]=a[i]

那么,对于1到r的区间和,即为:

 a[1]+a[2]+……+a[r-1]+a[r]
//用上方公式推导得出
=tree[1]+(tree[1]+tree[2])+……+(tree[1]+……+tree[r])
//根据加法交换律与结合律:
=(tree[1]*(r))+(tree[2]*(r-1))+……(tree[r]*1)
//那么:
=r*(tree[1]+tree[2]+……+tree[r])-(tree[1]*0+tree[2]*1+……+tree[r]*(r-1))

看到这里,是不是已经很清晰了呢?

对于a的树状数组(差分)tree,建立一个新的树状数组tree1使得:

tree1[i]=tree[i]*(i-1)

之后,x到y的区间和即为:

(y*query(tree,y)-(x-1)*query(tree,x-1))-(query(tree1,y)-query(tree1,x-1))

P3372 【模板】线段树 1

这种树状数组可以实现线段树的某些功能

#include<bits/stdc++.h>
#define rg register
#define inf 2147483647
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
#define ll long long
#define maxn 100005
const double eps=1e-8;
using namespace std;
inline ll read()
{
    char ch=getchar();ll s=0,w=1;
    while(ch<48||ch>57){if(ch=='-')w=-1;ch=getchar();}
    while(ch>=48&&ch<=57){s=(s<<1)+(s<<3)+ch-48;ch=getchar();}
    return s*w;
}
inline void write(ll x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)write(x/10);
    putchar(x%10+48);
}
ll n,m;
ll tree[maxn],tree1[maxn];
inline ll lb(ll x)
{
    return x&-x;
}
inline void add(ll *tree,ll x,ll k)
{
    for(;x<=n;x+=lb(x))
    {
        tree[x]+=k;
    }
}
inline ll query(ll *tree,ll x)
{
    ll ans=0;
    for(;x;x-=lb(x))
    {
        ans+=tree[x];
    }
    return ans;
}
int main()
{
    n=read(),m=read();
    ll now,last=0;
    for( rg ll i=1;i<=n;i++)
    {
        now=read();
        add(tree,i,now-last);
        add(tree1,i,(now-last)*(i-1));
        last=now;
    }
    for(rg ll i=1;i<=m;i++)
    {
        ll x;
        x=read();
        if(x==1)
        {
            ll a,b,c;
            a=read(),b=read();c=read();
            add(tree,a,c);
            add(tree,b+1,-c);
            add(tree1,a,c*(a-1));
            add(tree1,b+1,-c*b);
        }
        else if(x==2)
        {
           ll  a,b;
           a=read(),b=read();
           cout<<b*query(tree,b)-(a-1)*query(tree,a-1)-(query(tree1,b)-query(tree1,a-1))<<endl;
        }
    }
    return 0;
}