树状数组模板

树状数组模板_第1张图片

我们也不难发现,这个k就是该节点在树中的高度,因而这个树的高度不会超过logn。

          所以,当我们修改A[i]的值时,可以从C[i]往根节点一路上溯,调整这条路上的所有C[]即可,

          这个操作的复杂度在最坏情况下就是树的高度即O(logn)。  

          另外,对于求数列的前n项和,只需找到n以前的所有最大子树,把其根节点的C加起来即可。

          不难发现,这些子树的数目是n在二进制时1的个数,或者说是把n展开成2的幂方和时的项数,

          因此,求和操作的复杂度也是O(logn)。

 

接着,我们考察这两种操作下标变化的规律:

          首先看修改操作:

          已知下标i,求其父节点的下标。
          我们可以考虑对树从逻辑上转化:

       树状数组模板_第2张图片

 

如图,我们将子树向右对称翻折,虚拟出一些空白结点(图中白色),将原树转化成完全二叉树。

         有图可知,对于节点i,其父节点的下标与翻折出的空白节点下标相同。

         因而父节点下标 p=i+2^k  (2^k是i用2的幂方和展开式中的最小幂,即i为根节点子树的规模)

         即  p = i + i&(i^(i-1)) 。 

         接着对于求和操作:

         因为每棵子树覆盖的范围都是2的幂,所以我们要求子树i的前一棵树,只需让i减去2的最小幂即可。

 

 

 

 

/*树状数组的缺点实不能求某一区间的最值
c1=a1;
c2=a1+a2;
c3=a3;
c4=a1+a2+a3+a4;
c5=a5;
c6=a5+a6;
c7=a7;
c8=a1+a2+a3+a4+a5+a6+a7+a8;
......
c2^n=a1+a2+....+a2^n;

c[x]=a[x-2^k+1]+...+a[x];//总共2^k个;k为x的的二进制表示的末尾的0的个数

注:改变a[x]时只需改变c[x],c[x+lowbit(x)],c[x+lowbit(x)+lowbit(x+lowbit(x))]....;???????

*/

#include
#define N 100
int n;
int c[N];
int a[N];
int lowbit(int x)//)//返回x二进制最右边1;即t=2^k;k为x的的二进制表示的末尾的0的个数
//求一个数x的的二进制表示的末尾的0的个数2^k=x&(x^(x-1));
{
 int lb;
 return lb=x&(x^(x-1));//等价于lb=(-x)&x;
}

void change(int k,int delta)//注:这里的detal是指a[k]变化了detal;
{
 //更新包含C[i]的所有C[k]???????
 while(k {
  c[k]=c[k]+delta;
  k=k+lowbit(k);
 }
}

int getsum(int k)//返回sum[k]=(a[1]+...a[k]);即c[x]+c[x-lowbit(x)]+c[i-lowbit(x)-lowbit(x-lowbit(x))].....lowbit(x)=2^k;????????
{
 int t=0;
 while(k>0)
 {
  t=t+c[k];//C[i]=C[i-2^k+1]+...+C[i]
  k=k-lowbit(k);
 }
 return t;
}

/*列:对a[]={2,5,3,4,1},求b[i]=位置i左边小于等于a[i]的数的个数;只需对任意
a[i]每次getsum(a[i]),再updeta(a[i],1)即可;

但是,如果求的是b[i]=位置i左边大于等于a[i]的数的个数;这要改变函数:update变为每次k-lowbit(k);而getsum变成k+lowbit(k),于前面正好相反(看图理解)

在数据范围较大时,应用离散化处理;a[]={1000000,10,2000,20,300};离散化后a[]={5,1,4,2,3}.
*/

 


/*二维树状数组

c[x][y]=sum(a[i][j]);
x-lowbit(x)+1<=i<=x,
y-lowbit(y)+1<=j<=y.

//修改a[x][y]
void change(int x,int y,int delta)
{
for(int i=x;i for(int j=y;j  c[i][j]+=delta;
}

//查询sum(a[1][1]+...a[i][j])
int getsum(int i,int j)
{
 int result=0
 for(int x=i;x>0;x-=lowebit(x))
  for(int y=j;y>0;y-=lowebit(y))
   result+=c[x][y];
  return result;

}

*/

 

 

 

 

你可能感兴趣的:(acm—数据结构)