树状数组&线段树 的奇妙用法

树状数组&线段树 的奇妙用法

树状数组只支持单点加,前缀查询,那么不妨通过一些奇妙的途径转化树状数组的性质(因为常数巨小)。

代码和数组定义如下:

I s[maxn],n;//n 为树状数组值域最大值
void pls(I x,I y){
    for(;x<=n;x+=x&-x)s[x]+=y;
}I sum(I x){
    I ans=0;
    for(;x;x-=x&-x)ans+=s[x];
    return ans;
}

1.区间加,单点查询

树状数组维护差分数组即可。区间 [ l , r ] [l,r] [l,r] k k k ,就只需给 l l l 位置加上 k k k r + 1 r+1 r+1 位置加上 k k k ;单点查询的时候就查询 [ 1 , x ] [1,x] [1,x] 的前缀和即可。

2.区间加,区间求和

从上一个思路出发开始乱搞(虽然线段树秒杀,但是还是有点常数而且结构上可能会有问题不好找)、

我们设 c [ i ] c[i] c[i] 为差分数组,区间求和目标就是 ∑ i = l r ∑ j = 1 i c [ j ] \sum\limits_{i=l}^r \sum\limits_{j=1}^i c[j] i=lrj=1ic[j]

发现不太好直接求解,于是转化成 [ 1 , r ] [1,r] [1,r] 的和减去 [ 1 , l − 1 ] [1,l-1] [1,l1] 的和。这里以 [ 1 , r ] [1,r] [1,r] 的求和为例。

原式= ∑ i = 1 r ∑ j = 1 i c [ j ] \sum\limits_{i=1}^r\sum\limits_{j=1}^i c[j] i=1rj=1ic[j] ,交换主体,可得 j j j 能够取 [ 1 , r ] [1,r] [1,r] 之中所有数,而每个 j j j 出现了 r − j + 1 r-j+1 rj+1 次。

式子就变成了 ∑ j = 1 r c [ j ] × ( r − j + 1 ) \sum\limits_{j=1}^r c[j]\times (r-j+1) j=1rc[j]×(rj+1) 。把可控的部分分离出来,得到 ( r + 1 ) × ∑ j = 1 r c [ j ] − ∑ j = 1 r j × c [ j ] (r+1)\times \sum\limits_{j=1}^r c[j] -\sum\limits_{j=1}^r j\times c[j] (r+1)×j=1rc[j]j=1rj×c[j]

所以维护两个数组,一个 c [ j ] c[j] c[j] ,一个 c [ j ] × j c[j]\times j c[j]×j 即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值