小结树状数组

前言

这篇博客算是对树状数组应用的总结,并不是树状数组的讲解。

单点修改-区间查询

这就是最普通的树状数组,区间查询我们查询前缀和之后减掉就能得解。

void add(int x,int data){
    for (int i=x;i<=n;i+=i&-i) T[i]+=data;
}
int query(int x){   
    for (int i=x;i;i-=i&-i) ret+=T[x];
    return ret;
}   

区间修改-单点查询

我们运用差分的思想,我们把原先T表示原数组改为表示差分数组,这样我们单点查询就变成了查询前缀和,而区间修改就变成了两个端点上的单点修改了,那么就和第一个操作一样了。

区间修改-区间查询

这个功能非常的强大,而且用树状数组实现相较与线段树常数很小,所以非常好用,而且代码非常的简短。
我们还是利用差分的思想,我们用delta[i]表示区间i..n加上delta[i]的值,那么我们的前缀和就可以表示为
sum[i]=a[1]+a[2]+...+a[i]+delta[1]i+delta[2](i1)+...+delta[i]1 s u m [ i ] = a [ 1 ] + a [ 2 ] + . . . + a [ i ] + d e l t a [ 1 ] ∗ i + d e l t a [ 2 ] ∗ ( i − 1 ) + . . . + d e l t a [ i ] ∗ 1
化简一下
sum[i]=sigma(a[x])+sigma(delta[x](i+1x))(1<=x<=i) s u m [ i ] = s i g m a ( a [ x ] ) + s i g m a ( d e l t a [ x ] ∗ ( i + 1 − x ) ) ( 1 <= x <= i )
re化简一波
sum[i]=sigma(a[x])+(i+1)sigma(delta[x])sigma(delta[x]x)(1<=x<=i) s u m [ i ] = s i g m a ( a [ x ] ) + ( i + 1 ) ∗ s i g m a ( d e l t a [ x ] ) − s i g m a ( d e l t a [ x ] ∗ x ) ( 1 <= x <= i )
我们发现 sigma(a[x]) s i g m a ( a [ x ] ) 很好处理,直接前缀和一波
sigma(delta[x]) s i g m a ( d e l t a [ x ] ) sigma(delta[x]x) s i g m a ( d e l t a [ x ] ∗ x ) 都可以用树状数组维护区间修改单点查询完成,那么我们就解决了这个问题

inline void add(int x,int y){
    LL add1=y,add2=x*y;
    for (int i=x;i<=n;i+=i&-i)
        T1[i]+=add1,T2[i]+=add2;
}
inline LL query(LL x){
    LL sum1=0,sum2=0;
    for (int i=x;i>0;i-=i&-i){
        sum1+=T1[i],sum2+=T2[i];
    }
    return sum1*(x+1)-sum2;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值