树状数组的一些理解

99封情书 提交于 2020-01-14 11:04:48

树状数组中的lowbitlowbit的一些具体意思,有一点感悟。

原理:这个百度上都有,就不说了。

假设树状数组为c[]c[],原数组为a[]a[]1i1-i的和数组为sum[i]sum[i]
则经过观察有:
c[i]=a[i2k+1]+a[i2k+2]+...+a[i]c[i]=a[i-2^{k}+1]+a[i-2^{k}+2]+...+a[i]
sum[i]=c[i]+c[i2k1]+c[i2k12k2]+...+c[0]sum[i]=c[i]+c[i-2^{k1}]+c[i-2^{k1}-2^{k2}]+...+c[0]

这里的lowbit(x)lowbit(x)有两种求法:
lowbit(x)=(x)and(x)lowbit(x)=(x )and( -x)
lowbit(x)=(x)xor(x1)lowbit(x)=(x)xor(x-1)

y=x+lowbit(x)y=x+lowbit(x):此时的yy,在树状数组的图形中,就是xx的父亲节点,也就是yy包括xx的覆盖范围。

在这里插入图片描述

y=xlowbit(x)y=x-lowbit(x):此时的yy,在树状数组的图形中就是一个相邻的节点。

在这里插入图片描述
树状数组可以支持:
1.单点修改,区间查询
2.区间修改,单点查询
3.区间修改,区间查询
4.区间最值
5.二维树状数组

1.单点修改,区间查询:

树状数组的元素代表对应区间a[i]a[i]的和,可能需要离散化。

2.区间修改,单点查询:

这个需要转化到差分的形式,树状数组的每个元素维护对应区间a[i]a[i1]a[i]-a[i-1]的值。

3.区间修改,区间查询:

这个就需要推导一下了。
首先,令d[i]=a[i]a[i1]d[i]=a[i]-a[i-1]
i=1na[i]=k=1n(i=1kd[i]+a[0])a[0]=0\sum_{i=1}^n a[i]=\sum_{k=1}^n(\sum_{i=1}^k d[i] +a[0]),a[0]=0
化简后为:
i=1na[i]=k=1n(ni+1)d[i]=(n+1)i=1nd[i]i=1nid[i]\sum_{i=1}^na[i]\\ =\sum_{k=1}^n (n-i+1)*d[i]\\ =(n+1)*\sum_{i=1}^nd[i]-\sum_{i=1}^ni*d[i]
因此,维护一下d[i]d[i]id[i]i*d[i]就可以了。

4.区间最值:

(HDU 1754)
这里可以考虑附上核心代码:

void update(int pos){
		while(pos<=N){
			t[pos]=a[pos];
			int y=lowbit(pos);
			for(int i=0;(1<<i)<y;++i) t[pos]=max(t[pos],t[pos-(1<<i)]);
			pos+=y;
		}
	}

	int query(int l,int r){
		int ans=0;
		//cout<<l<<" "<<r<<endl;
		while(l<=r){
			//cout<<r<<" "<<r-lowbit(r)+1<<" "<<l<<" "<<t[r]<<endl;
			if(r-lowbit(r)+1>=l) ans=max(ans,t[r]),r-=lowbit(r);
			else ans=max(ans,a[r]),--r;
		}
		return ans;
	}

解释一下核心部分,这里有两个数组a[]a[]表示数组中的值,t[]t[]表示树状数组中对应的区间的最大值。
对于updateupdate中的一段:

for(int i=0;(1<<i)<y;++i) t[pos]=max(t[pos],t[pos-(1<<i)]);

这里是在枚举树状数组中某个节点的所有子节点,想象一下,这些节点pos(1<<i)pos-(1<<i)lowbitlowbit一定为1<<i1<<i,所以加上以后一定会pospos

对于queryquery中的一段:

if(r-lowbit(r)+1>=l) ans=max(ans,t[r]),r-=lowbit(r);	
else ans=max(ans,a[r]),--r;

这里主要是在考虑该节点能不能完全包含在区间内,如果能就比较答案与这段区间的值,如果不能,就一个一个的枚举。

5.二维树状数组

对于xx的每个节点,再开一个树状数组来进行记录yy的信息。
可以用树套树等代替。
统计的是一个正方形方块内的和。(1n,1m)(1-n,1-m)

附上代码:

struct Tree_array{
	LL t[maxn];

	void init(){ memset(t,0,sizeof t); }

	void update(int pos,int num){
		while(pos<=N){
			t[pos]+=num;
			pos+=lowbit(pos);
		}
	}

	LL query(int pos){
		LL sum=0;
		while(pos){
			sum+=t[pos];
			pos-=lowbit(pos);
		}
		return sum;
	}
}T[maxn];

void update(int x,int y,int z){
	while(x<=N){
		T[x].update(y,z);
		x+=lowbit(x);
	}
}

LL query(int x,int y){
	LL sum=0;
	while(x){
		sum+=T[x].query(y);
		x-=lowbit(x);
	}
	return sum;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!