一、树状数组
树状数组可以在logn的时间内求出一段连续区间的和,特别对于多次修改后再求值,树状数组就显得尤为重要了。
for(int i=x;i<=maxn;i+=lowbit(i))
{
C[i]+=val;
}
求和:
和第i项有关的项都在前面,所以求和操作就是
for(int i=x;i;i-=lowbit(i))
{
ans+=tree[i];
}
比如求前11项的和,转换为C[11]+C[10]+C[8],这样就不会漏项了。
注意:
树状数组一定从第一项开始,所以在做题的时候一样要注意原数组的开始位置。
二、二维树状数组
给定一个矩阵,然后会修改某个值,再问你某个子矩阵的和
其实也很容易,同样的定义一个树状数组C[][]
则有:
其实就是行和列上都来一次树状数组,对于第i行的,根据lowbit(i)包含前面的项,对于第j列的,其实和一维树状数组一样了。
更新:
void add(int x,int y)
{
for (int i=x;i<=N;i+=lowbit(i))
for (int j=y;j<=N;j+=lowbit(j))
C[i][j]++;
求和:
int sum(int x,int y)
{
int ans=0;
for (int i=x;i;i-=lowbit(i))
for (int j=y;j;j-=lowbit(j))
ans+=tree[i][j];
return ans;
}
感想
巧妙地利用树状数组,可以解决很多问题,而且其效率也很高,是一种很神奇的数据结构,树状数组灵活多变,个人认为活学活用还是挺有难度的......多做题,争取提高这方面的能力吧!