树状数组一(二)维区间修改与求和

39 篇文章 6 订阅
12 篇文章 0 订阅

首先考虑树状数组的一维区间修改与求和
把数列差分,那么对l和r的区间加就可以变成l位置的加和r+1的减
设差分数组为t
修改前数组为a
修改后数组为b
那么修改后的答案

ans=i=lrb[l]=i=lra[i]+b[i](ri+1)=(r+1)i=lra[i]+b[i]i=lra[i]i

a[i]提前处理好,分别用两个树状数组维护 ri=lb[i] ri=la[i]i
一维还是很简单的


二维略复杂一些
这次直接忽略a,式子里也不写了
树状数组中的[x,y]为[1,1]~[x,y]的结果
对于[x1,y1,x2,y2]相当于在四个角的位置分别加减
具体来说就是[x2,y2]-[x2,y1-1]-[x1-1,y2]+[x2-1,y2-1]
这是对于查询
对于修改是修改[x,y]到[n,m]的东西的
所以设x为增加值,对于修改就相当于分别做下面四个东西
[x1,y1]+x,[x1,y2+1]-x,[x2,y1+1]-x,[x2+1,y2+1]+x

ans=i=1xj=1yb[i][j](xi+1)(yj+1)=(x+1)(y+1)i=1xj=1yb[i][j](y+1)i=1xj=1yb[i][j]i(x+1)i=1xj=1yb[i][j]j+i=1xj=1yb[i][j]ij

那么,用四个树状数组分别存下
xi=1yj=1b[i][j]
xi=1yj=1b[i][j]i
xi=1yj=1b[i][j]j
xi=1yj=1b[i][j]ij
求值即可
代码如下

ll get(ll z,ll x,ll y)
{
    ll ans=0;
    for(ll i=x;i;i-=lowbit(i)) for(ll j=y;j;j-=lowbit(j)) ans+=t[z][i][j];
    return ans;
}
ll sum(ll x,ll y)
{
    return (((x+1)*(y+1)*get(0,x,y))%mo-((x+1)*get(2,x,y))%mo-((y+1)*get(1,x,y))%mo+get(3,x,y)+mo+mo)%mo;
}
void put(ll z,ll x,ll y,ll w)
{
    for(ll i=x;i<=n;i+=lowbit(i)) for(ll j=y;j<=m;j+=lowbit(j)) t[z][i][j]+=w;
}
void ins(ll x,ll y,ll w)
{
    put(0,x,y,w);
    put(1,x,y,w*x);
    put(2,x,y,w*y);
    put(3,x,y,w*x*y);
}
int main()
{
    ins(x1,y1,x);ins(x1,y2+1,-x);ins(x2+1,y1,-x);ins(x2+1,y2+1,x);//加入
    ans=sum(x,y)-sum(x,y1-1)-sum(x1-1,y)+sum(x1-1,y1-1);//查询
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值