树状数组中的的一些具体意思,有一点感悟。
原理:这个百度上都有,就不说了。
假设树状数组为,原数组为,的和数组为。
则经过观察有:
这里的有两种求法:
:此时的,在树状数组的图形中,就是的父亲节点,也就是包括的覆盖范围。
:此时的,在树状数组的图形中就是一个相邻的节点。
树状数组可以支持:
1.单点修改,区间查询
2.区间修改,单点查询
3.区间修改,区间查询
4.区间最值
5.二维树状数组
1.单点修改,区间查询:
树状数组的元素代表对应区间的和,可能需要离散化。
2.区间修改,单点查询:
这个需要转化到差分的形式,树状数组的每个元素维护对应区间的值。
3.区间修改,区间查询:
这个就需要推导一下了。
首先,令
化简后为:
因此,维护一下和就可以了。
4.区间最值:
(HDU 1754)
这里可以考虑附上核心代码:
void update(int pos){
while(pos<=N){
t[pos]=a[pos];
int y=lowbit(pos);
for(int i=0;(1<<i)<y;++i) t[pos]=max(t[pos],t[pos-(1<<i)]);
pos+=y;
}
}
int query(int l,int r){
int ans=0;
//cout<<l<<" "<<r<<endl;
while(l<=r){
//cout<<r<<" "<<r-lowbit(r)+1<<" "<<l<<" "<<t[r]<<endl;
if(r-lowbit(r)+1>=l) ans=max(ans,t[r]),r-=lowbit(r);
else ans=max(ans,a[r]),--r;
}
return ans;
}
解释一下核心部分,这里有两个数组表示数组中的值,表示树状数组中对应的区间的最大值。
对于中的一段:
for(int i=0;(1<<i)<y;++i) t[pos]=max(t[pos],t[pos-(1<<i)]);
这里是在枚举树状数组中某个节点的所有子节点,想象一下,这些节点的一定为,所以加上以后一定会。
对于中的一段:
if(r-lowbit(r)+1>=l) ans=max(ans,t[r]),r-=lowbit(r);
else ans=max(ans,a[r]),--r;
这里主要是在考虑该节点能不能完全包含在区间内,如果能就比较答案与这段区间的值,如果不能,就一个一个的枚举。
5.二维树状数组
对于的每个节点,再开一个树状数组来进行记录的信息。
可以用树套树等代替。
统计的是一个正方形方块内的和。
附上代码:
struct Tree_array{
LL t[maxn];
void init(){ memset(t,0,sizeof t); }
void update(int pos,int num){
while(pos<=N){
t[pos]+=num;
pos+=lowbit(pos);
}
}
LL query(int pos){
LL sum=0;
while(pos){
sum+=t[pos];
pos-=lowbit(pos);
}
return sum;
}
}T[maxn];
void update(int x,int y,int z){
while(x<=N){
T[x].update(y,z);
x+=lowbit(x);
}
}
LL query(int x,int y){
LL sum=0;
while(x){
sum+=T[x].query(y);
x-=lowbit(x);
}
return sum;
}
来源:CSDN
作者:South-twilight
链接:https://blog.csdn.net/qq_35776579/article/details/103953666