树状数组(求前缀和的利器)已同步
标签:ACM
一维树状数组
//bt[i]和bt[j]管辖的区间之间要么是完全包含的,要么是不重叠的
//b[i]覆盖的长度是lowbit(i)
int bt[maxn];//树状数组,下标必须从1开始,不然lowbit(0)=0会出现死循环
#define lowbit(i) ((x)&(-x))
void update(int x,int v)//第x个数加上v,沿着 右上 的路径前进的,不断定位最右边1的左边0的过程
{
for(int i=x;i<=n;i+=lowbit(i))//最近的包含i的区间是i+lowbit(i),
bt[i]+=v;
}
//注意点:求第4到第9个数时,不能直接将i>0改为i>=4(会算进多余的数,性质),应该getsum(9)-getsum(4-1)
int getsum(int x)//前x个数之和,沿着左上前进,不断把x的最右边的1置0的过程
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
sum+=bt[i];
return sum;
}
二维及以上的树状数组
//如果单独把二维中的第一个维度拿出来A[1][m] + A[2][m] = C[2][m],A[3][m] = C[3][m],
//是不是也和一维的数组一样,所以二维数组的规律就是,不管是横坐标还是纵坐标,将他们单独拿出来,他们都符合x += lowbit(x),属于它的父亲节点
int bt[maxn][maxn];//树状数组,下标必须从1开始,不然lowbit(0)=0会出现死循环
#define lowbit(i) ((x)&(-x))
void update(int x,int y,int v)//第x个数加上v,沿着 右上 的路径前进的,不断定位最右边1的左边0的过程
{
for(int i=x;i<=n;i+=lowbit(i))//最近的包含i的区间是i+lowbit(i),
for(int j=y;j<=n;j+=lowbit(j))
bt[i][j]+=v;
}
//注意点:求第4到第9个数时,不能直接将i>0改为i>=4(会算进多余的数,性质),应该getsum(9)-getsum(4-1)
int getsum(int x,int y)//前x个数之和,沿着左上前进,不断把x的最右边的1置0的过程
{
int sum=0;
for(int i=x;i>0;i-=lowbit(i))
for(int j=y;j>0;j-=lowbit(j))
sum+=bt[i][j];
return sum;
}
区间更新,单点查询
//跟区间查询,单点更新正好相反
int bt[maxn];
int n;
int update(int x,int v){//前x个整数都加上v
for(int i=x;i>0;i-=lowbit(i))
c[i]+=v;
}
int getnum(int x){//返回第i个数的值
int ans=0;
for(int i=x;i<=n;i+=lowbit(i))
ans+=bt[i];
return ans;
}