一维树状数组常用的3个函数
int lowbit(int x) //取x的最低位1,比如4,则返回4,如5,则返回1
{
return x&(-x);
}
void update(int i, int val) //将第i个元素增加val
{
//i的祖先都要增加val
while(i <= n)
{
sum[i] += val;
i += lowbit(i); //将i的二进制未位补为得到其祖先
}
}
int Sum(int i) //求前i项的和
{
int s = 0;
//将前i项分段
while(i > 0)
{
s += sum[i];
i -= lowbit(i); //去掉i的二进制最后一个
}
return s;
}
以下数组下标均默认从1开始
应用一
假如给你一个数组a[ ] = {2,5,3,4,1},求b[i],b[i] 表示在a[1],a[2]...a[i-1]中(即位置i的左边)小于等于a[i]的数的个数。对此例b[] = {0,1,1,2,0}。 那么该如何去求得b[i]呢?
解法:假如要得到b[4]的值,对于a[4] = 4. 我们 只要得到在a[1],a[2],a[3] 中出现小于等于4的个数,即1,2,3,4的个数,此例即为2. a[1] = 2 < a[4], a[3] = 3 < a[4]. 所以b[4] = 2;其他的以此类推. 求b[i]的值,需要得到在a[1],a[2]....a[i-1]中出现小于等于a[i]的个数,即1,2...a[i]的个数. 相当于求前a[i]项的和,可用到树状数组.
具体操作
for(int i=1; i<=n; i++)
{
b[i] = getSum(a[i]); //求前a[i]项的和
update(a[i],1); //第a[i]个元素+1
}
应用二
假如给你一个数组a[ ] = {2,5,3,4,1},求b[i],b[i] 表示在a[1],a[2]...a[i-1]中(即位置i的左边)大于等于a[i]的数的个数。对此例b[] = {0,0,1,1,4}。 那么该如何去求得b[i]呢?
解法1: 只需要先将数组a倒过来编号,即将a转换为,a[] ={4,1,3,2,5}.此时具体的操作如应用一
解法2:改变更新路径和求和路径
void update(int x, int val)
{
for(int i=x; i>0; i-=lowbit(i))
{
sum[i] += val;
}
}
int getSum(int x)
{
int s = 0;
for(int i=x; i<MAXN; i+=lowbit(i))
{
s += sum[i];
}
return s;
}
应用三 逆序数
假如给你一个数组a[ ] = {2,5,3,4,1},求b[i],b[i] 表示在a[i],a[i+1]...a[n]中(即位置i的右边)小于等于a[i]的数的个数。对此例b[] = {1,3,1,1,0}。 那么该如何去求得b[i]呢?
操作:应用一位置i的左边,应用三是位置i的右边。 然后只需要在应用一的基础上从后往前操作即可
for(int i=n; i>=1; i--)
{
b[i] = getSum(a[i]); //求前a[i]项的和
update(a[i],1); //第a[i]个元素+1
}
应用四
假如给你一个数组a[ ] = {2,5,3,4,1},求b[i],b[i] 表示在a[i],a[i+1]...a[n]中(即位置i的右边)大于等于a[i]的数的个数。对此例b[] = {3,0,1,0,0}。 那么该如何去求得b[i]呢?
操作:只需将数组a倒过来编号,即将a转化为 a[]={4,1,3,2,5} 然后利用应用三
二维树状数组
int lowbit(int x)
{
return x&(-x);
}
void update(int x, int y, int val) //将 a[x][y] 的值增加val
{
for(int i=x; i<N; i+=lowbit(i))
{
for(int j=y; j<N; j+=lowbit(j))
{
sum[i][j] += val;
}
}
}
int getSum(int x, int y) //求以1,1为左上角端点,学校,x,y为右下角端点的矩阵和.
{
int s = 0;
for(int i=x; i>0; i-=lowbit(i))
{
for(int j=y; j>0; j-=lowbit(j))
{
s += sum[i][j];
}
}
return s;
}