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

本文介绍树状数组在区间加单点查询及区间加区间求和的应用技巧,利用差分数组进行转化,实现高效查询和更新操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

代码和数组定义如下:

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]kkk ,就只需给 lll 位置加上 kkkr+1r+1r+1 位置加上 kkk ;单点查询的时候就查询 [1,x][1,x][1,x] 的前缀和即可。

2.区间加,区间求和

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

我们设 c[i]c[i]c[i] 为差分数组,区间求和目标就是 ∑i=lr∑j=1ic[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=1r∑j=1ic[j]\sum\limits_{i=1}^r\sum\limits_{j=1}^i c[j]i=1rj=1ic[j] ,交换主体,可得 jjj 能够取 [1,r][1,r][1,r] 之中所有数,而每个 jjj 出现了 r−j+1r-j+1rj+1 次。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值