您的位置:首页 > 其它

【黑科技】用树状数组解决区间修改查询问题

2017-08-14 21:55 246 查看
遇到区间查询修改,相信大家一般用的都是线段树,

但常数远远没有树状数组优秀,

这里就来谈谈如何用树状数组解决区间问题

(同时可以用于多维问题)

首先,相信大家一定会用树状数组做区间加,单点查询的问题,

差分一下即可;

那么对于区间查询,怎么做呢?

要做到区间查询,就要能计算一个点的值对后面的值的影响,

多开一个数组F[i]=(n-i+1)*f[i],(f为用来差分的数组)

差分的话当然是这个点的值对后面的每个点都有影响,所以权值乘上那么多,

但很显然,在计算区间是,它的影响没有那么大,

设查询的区间是l,r,那么它在答案中应该是:(r−i+1)∗f[i]=F[i]−(n−r)∗f[i],

发现(n-r)对于任意的f[i]都是一定的,也就是可以区间求和以后直接乘上(n-r)减掉F多出来的部分,再加上l之前的影响,

这样既可实现用树状数组解决区间修改查询问题,

那么现在问题来了,如何用树状数组实现二维或多维的求和,

以二维为例,

对平面上的一个矩形加/减,求矩形里点的和,

我们需要多开3个数组,

F1[i][j]=(m-j+1)*(n-i+1)*f[i],

F2[i][j]=(n-i+1)*f[i],

F3[i][j]=(m-j+1)*f[i],

用矩阵和的套路,减掉右边左边,加上右下角的,即可,

对于前面的影响,与处理后面的差不多,

(这个需要大家自己感受一下,实在不会就看标吧)

(重点在Gans这个函数)

void change(int x,int y,int e)
{
if(x>n||y>m)return;
for(int i=x;i<=n;i+=NX(i))
for(int j=y;j<=m;j+=NX(j))
{
f[i][j]+=e;
f1[i][j]=(f1[i][j]+e*(n-x+1)*(m-y+1))%mo;
f2[i][j]=(f2[i][j]+e*(n-x+1))%mo;
f3[i][j]=(f3[i][j]+e*(m-y+1))%mo;
}
}
void find(int x,int y)
{
fd1=fd2=fd3=fd=0;
for(int i=x;i;i-=NX(i))
for(int j=y;j;j-=NX(j))
{
fd+=f[i][j];
fd1=(fd1+f1[i][j])%mo;
fd2=(fd2+f2[i][j])%mo;
fd3=(fd3+f3[i][j])%mo;
}
}
void add(int x,int y,int x1,int y1)
{
change(x,y,1);
change(x,y1+1,-1);
change(x1+1,y,-1);
change(x1+1,y1+1,1);
}
int Gans(int x,int y,int x1,int y1)
{
LL s,s1,s2,s3;
find(x-1,y1);s=fd,s1=fd1,s2=fd2,s3=fd3;
find(x-1,y-1);s-=fd,s1-=fd1,s2-=fd2,s3-=fd3;
LL t=0;
t=(s3-s*(m-y1))%mo*(x1-x+1)%mo;
find(x1,y-1);s=fd,s1=fd1,s2=fd2,s3=fd3;
find(x-1,y-1);s-=fd,s1-=fd1,s2-=fd2,s3-=fd3;
t=(t+(s2-s*(n-x1))%mo*((y1-y+1))%mo)%mo;
find(x-1,y-1);s=fd,s1=fd1,s2=fd2,s3=fd3;
t=(t+s*(y1-y+1)%mo*(x1-x+1))%mo;//这是前面的影响

find(x1,y1);s=fd,s1=fd1,s2=fd2,s3=fd3;
find(x-1,y1);s-=fd,s1-=fd1,s2-=fd2,s3-=fd3;
find(x1,y-1);s-=fd,s1-=fd1,s2-=fd2,s3-=fd3;
find(x-1,y-1);s+=fd,s1+=fd1,s2+=fd2,s3+=fd3;
s1=s1-s3*(n-x1)-s2*(m-y1);s1=(s1%mo+mo)%mo;
s=s%mo;
s1=(s1+(n-x1)*(m-y1)%mo*s)%mo;
return (s1+t)%mo;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐