树状数组:
C[i]数组的理解:
图一:
如何计算C数组?(数组下标用二进制表示,尾部有n个0,c数组就等于n+1个相加)
- 二进制末尾为1,则为本身,如c[1],c[11],c[101];
- 若末尾有0,则依次将末尾的0依次变为1,并累加起来就是c数组,如c[10100]=c[10010]+c[10011]+a[10100];(即10100的中的00依次变为1,得10和11,然后加上前的101-1=100,得10010,和10011.
c[1]:c[1]=c[1]
c[2]:c[10]=c[1]+a[10];
c[3]:c[11]=a[11];
c[4]:c[100]=c[10]+c[11]+a[100];
c[5]:c[101]=a[101];
c[6]:c[110]=c[101]+a[110];
c[7]:c[111]=a[111];
c[8]:c[1000]=c[100]+c[110]+c[111]+a[1000];
如何计算一个数de 尾部有多少个0
根据补码性质有:x^(-x)
或者:x&(x^(x-1))
注意这里返回的是二进制,如x=100(二进制),返回的是100,值是4,因为后续就是用的这个,再如x=10100(二进制)返回的是100,值是4.。
代码
int lowbit(int x)
{
return x^(-x);
//return x&(x^(x-1));
}
初始输入
接下来是如何进行数据的输入,和对c[i]数组的维护
因为树状数组中的c[i]数组保存的是前面数据的和,故输入一个数据,只会对后面的数组有影响。比如在上面的图一中,输入数据a[4],只会对c[4]和c[8]有影响。可以发现如a[11],a[100],a[110],先更新本身c[11],c[100],c[110],然后在更新上一层,分别为c[100],c[1000],c[1000].依次向上更新,每次只需在x基础上加lowbit(x)
实现代码:
void update(int x,int val)//x节点的值为val
{
while(x<MAX)//MAX为c数组上限
{
c[i]+=val;
x+=lowbit(x);
}
}
求和
求出区间1~x的和
sum=0;
例如求x=1000:
sum+=c[1000]
再比如求x=110,可以根据图一看出等于c[110]+c[100],即
- sum+=c[x];
- sum+=c[x-lowbit(x)]
实现代码
int add(int x)
{
int sum=0;
while(x>0)
{
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
若求[a,b]区间的和则为add(b)-add(a-1)
二维树状数组
二维树状数组,简单讲就是在update,add函数中while里再嵌套一个while,具体看代码:
int Row=100;
int Col=100;
int lowbit(int x)
{
return x&(-x);
}
void update(int i,int j,int val)
{
while(i<=Row)
{
int tj=j;
while(tj<=Col)
{
c[i][tj]+=val;
tj+=lowbit(tj);
}
i+=lowbit(i);
}
}
int add(int i,int j)//计算矩形(1,1)~(i,j)的和
{
int sum=0;
while(i>0)
{
int tj=j;
while(tj>0)
{
sum+=c[i][tj];
tj-=lowbit(tj);
}
i-=lowbit(i);
}
return sum;
}
例题:poj1656
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
int c[101][101];
int se[101][101];
string str;
int x,y,L;
int t;
int Row=100;
int Col=100;
int lowbit(int x)
{
return x&(-x);
}
void update(int i,int j,int val)
{
while(i<=Row)
{
int tj=j;
while(tj<=Col)
{
c[i][tj]+=val;
tj+=lowbit(tj);
}
i+=lowbit(i);
}
}
int add(int i,int j)
{
int sum=0;
while(i>0)
{
int tj=j;
while(tj>0)
{
sum+=c[i][tj];
tj-=lowbit(tj);
}
i-=lowbit(i);
}
return sum;
}
int main()
{
cin>>t;
while(t--)
{
cin>>str;
cin>>x>>y>>L;
if(str=="BLACK")
{
for(int i=x;i<x+L;i++)
for(int j=y;j<y+L;j++)
{
if(se[i][j]==1) continue;
else {
se[i][j]=1;
update(i,j,1);
}
}
}
else if(str=="WHITE")
{
for(int i=x;i<x+L;i++)
for(int j=y;j<y+L;j++)
{
if(se[i][j]==0) continue;
else {
se[i][j]=0;
update(i,j,-1);
}
}
}
else if(str=="TEST")
{
int sum=add(x+L-1,y+L-1)-add(x-1,y+L-1)-add(x+L-1,y-1)+add(x-1,y-1);
cout<<sum<<endl;
}
}
/* while(t--)
{
cin>>str;
if(str=="BLACK")
{
cin>>x>>y>>L;
for(int i=x;i<=x+L-1;i++)
for(int j=y;j<=y+L-1;j++)
f[i][j]=1;
}
else if(str=="WHITE")
{
cin>>x>>y>>L;
for(int i=x;i<=x+L-1;i++)
for(int j=y;j<=y+L-1;j++)
f[i][j]=0;
}
else if(str=="TEST")
{
cin>>x>>y>>L;
int cnt=0;
for(int i=x;i<=x+L-1;i++)
for(int j=y;j<=y+L-1;j++)
if(f[i][j]==1) cnt++;
cout<<cnt<<endl;
}
} */
return 0;
}